【发布时间】:2018-01-05 15:11:53
【问题描述】:
我有一个数组,假设 arr = [1, 2, 3, 4, 5, 6, 7, 8] 和另一个索引数组:idx = [0, 3, 4, 6]
我想得到两个数组,一个只是来自 arr 的那些索引: [1, 4, 5, 7] 剩下的就是另一个:[2, 3, 6, 8]
有人可以帮我吗?我只能想到丑陋的方法来做到这一点,但它必须是一些优雅地做到这一点的功能。
非常感谢!
【问题讨论】:
我有一个数组,假设 arr = [1, 2, 3, 4, 5, 6, 7, 8] 和另一个索引数组:idx = [0, 3, 4, 6]
我想得到两个数组,一个只是来自 arr 的那些索引: [1, 4, 5, 7] 剩下的就是另一个:[2, 3, 6, 8]
有人可以帮我吗?我只能想到丑陋的方法来做到这一点,但它必须是一些优雅地做到这一点的功能。
非常感谢!
【问题讨论】:
你可以这样做:
selected = [arr[i] for i in idx]
other = [v for i, v in enumerate(arr) if i not in idx]
如果arr 没有重复,你也可以这样做:
other = [v for v in arr if v not in selected]
【讨论】:
方法:
a1 = [arr[x] for x in idx]
a2 = [x for x in arr if x not in a1]
【讨论】:
一次遍历:
no, yes = both = [], []
for i, x in enumerate(arr):
both[i in idx].append(x)
或者(由 Chris_Rands 评论):
yes, no = [], []
for i, x in enumerate(arr):
(yes if i in idx else no).append(x)
虽然idx 应该要么很小,要么变成一个集合(其他答案中的解决方案也是如此,我猜他们只是不想谈论它)。
演示:
>>> if 1:
arr = [1, 2, 3, 4, 5, 6, 7, 8]
idx = [0, 3, 4, 6]
no, yes = both = [], []
for i, x in enumerate(arr):
both[i in idx].append(x)
print('yes', yes)
print('no', no)
yes [1, 4, 5, 7]
no [2, 3, 6, 8]
【讨论】:
both 重命名为 noyes 或 no_yes 会怎样?
numpy 有一个巧妙的解决方案:
import numpy as np
arr = np.asarray([1, 2, 3, 4, 5, 6, 7, 8]) # converts your list in numpy array
idx1 = [0, 3, 4, 6]
idx2 = [1, 2, 5, 7]
arr1 = arr[idx1] # [1 4 5 7]
arr2 = arr[idx2] # [2 3 6 8]
【讨论】:
您可以使用itertools 进行单行解决方案:
import itertools
arr = [1, 2, 3, 4, 5, 6, 7, 8]
idx = [0, 3, 4, 6]
[(out_index, not_in_arr), (in_index, in_arr)] = [(a, list(b)) for a, b in itertools.groupby(sorted(arr, key=lambda x:arr.index(x) in idx), key=lambda x:arr.index(x) in idx)]
print(not_in_arr)
print(in_arr)
输出:
[2, 3, 6, 8]
[1, 4, 5, 7]
【讨论】:
您还可以将arr 中的每个值映射到字典,指示它的索引是否存在于idx:
arr = [1, 2, 3, 4, 5, 6, 7, 8]
idx = [0, 3, 4, 6]
# converted to a set
idx_lookup = set(idx)
d = {x: True if i in idx_lookup else False for i, x in enumerate(arr)}
print(d)
这给出了这个字典:
{1: True, 2: False, 3: False, 4: True, 5: True, 6: False, 7: True, 8: False}
我还将idx 转换为集合,因为在这种情况下,不需要重复索引,集合/字典查找是O(1)。但是,列表查找是O(n),所以如果可能的话,这种优化是值得的。
一旦你有了这本字典,你就可以filter取出你想保留的元素,其余的元素从此:
keep = list(filter(lambda x: d[x], arr))
rest = list(filter(lambda x: not d[x], arr))
print(keep)
print(rest)
哪些输出:
[1, 4, 5, 7]
[2, 3, 6, 8]
注意:您还可以在keep 和rest 的过滤上方使用列表推导:
keep = [x for x in arr if d[x]]
rest = [x for x in arr if not d[x]]
【讨论】: