在numpy

时间:2018-05-29 17:25:03

标签: arrays list sorting numpy dictionary

假设我有以下numpy数组:

arr = numpy.array([[1, 7], [2, 0], [2, 1], [2, 3], [3, 4], [3, 5], [5, 6]])

假设我选择了一个特定的密钥,在本例中为2。然后我希望排序如下:

arr_sorted = [[2, 0], [2, 1], [2, 3], [1, 7], [3, 4], [3, 5], [5, 6]]

这个想法首先从键为2的所有元素开始,然后转到其键是上一个键值的条目。

从2开始,条目为[2, 0], [2, 1], [2, 3]。因此,2之后的下一个键将是0,1,3。没有条目以0作为键。有一个条目以1为密钥:[1, 7]。有两个条目,其中3为密钥:[3, 4], [3, 5]。下一个未处理的密钥是7,但它没有条目。同样适用于4.有一个条目,其中5为密钥:[5, 6]。 6没有条目。

是否有任何numpydictionary技巧可以达到此目的?

我最接近的尝试如下:

def bfs_finder(d, start):
  queue = deque([start])
  seen = [start]
  results = []
  while queue:
    _vertices = queue.popleft()
    current = [i for i, a in enumerate(d) if len([x for x in a if x in _vertices])==1 and i not in seen]
    curr1 = [a[1] for i, a in enumerate(d) if len([x for x in a if x in _vertices]) == 1 and i not in seen]
    if len(current)>0:
        results.extend(curr1)
        queue.extend(curr1)
        seen.extend(current)
  return results

但是,我实际上收到current = [i for i, a in enumerate(d) if len([x for x in a if x in _vertices])==1 and i not in seen] TypeError: argument of type 'int' is not iterable的错误。任何有关如何解决此错误的建议,以及是否有任何良好的改进都将受到高度赞赏。

1 个答案:

答案 0 :(得分:1)

您可以使用set来保存已处理的密钥和deque或类似的堆栈兼容容器来保存已处理的值(列表也可以使用)。由于您有numpy数组,您可以按行对数组进行预排序,并使用第一列上的np.searchsorted从中提取条带。

算法将是这样的:

  1. 按行排序
  2. 预分配输出数组
  3. 将密钥添加到stack
  4. 虽然堆栈不为空
    1. 从堆栈中弹出一个键
    2. 如果密钥在集合中,则丢弃并继续
    3. 向集合
    4. 添加密钥
    5. 使用bisection
    6. 在第一列(开始和结束索引)中查找关键字
    7. 如果存在密钥,请将swath复制到输出数组
  5. 排序操作是O(n log(n))。二分算法也是如此(大约n次搜索,每个O(log(n))。因此,您的算法复杂度不应超过O(n log(n)),这对于奇怪的排序算法非常有用。

    根据np.argsort使用this answer按行排序似乎最快,幸运的是np.searchsorted接受sorter参数。

    以下是一个示例实现:

    import numpy as np
    from collections import deque
    
    def bfs_finder(d, start):
        sorter = np.argsort(d[:, 0])
        done = set()
        todo = deque([start])
        output = np.empty_like(d)
        pos = 0
        while todo:
            key = todo.popleft()
            if key in done:
                continue
            done.add(key)
            left = np.searchsorted(d[:, 0], key, 'left', sorter)
            if left >= d.shape[0] or d[sorter[left], 0] != key:
                continue
            right = np.searchsorted(d[:, 0], key, 'right', sorter)
            next = pos + right - left
            output[pos:next, :] = d[sorter[left:right], :]
            todo.extend(output[pos:next, 1])
            pos = next
        return output
    
    arr = np.array([[1, 7], [2, 0], [2, 1], [2, 3], [3, 4], [3, 5], [5, 6]])
    print(bfs_finder(arr, 2))
    

    IDEOne Link

    [[2 0]
     [2 1]
     [2 3]
     [1 7]
     [3 4]
     [3 5]
     [5 6]]
    

    此解决方案假定输出中缺少原始密钥。如果遇到该问题,请从处理密钥集中减去第一列的集合,并确定如何处理剩余部分。

    您可以通过将整个堆栈传递给searchsorted的每次调用而不是一次只执行一个元素来获得额外的里程。