查找仅包含一组元素的更快方法?

时间:2019-08-18 16:28:41

标签: python

我想遍历组列表,并找到编号唯一/ 出现在列表中任何其他组中的任何组。

注意,该组列表代表数独板中的一行,每个组代表选项。如果只有一个元素,则代表船上那个位置的数字。

在下面的代码中,我定义了一个函数,该函数可以检查一个集合是否具有未出现在此列表的另一个集合中的数字。 但是,这很浪费,因为我将检查列表中包含多个元素的每个集合。

如何更改此/我可以使用哪些方法以更便宜的方式多次执行此操作?

def find_unique(sudoku_options, check_index):
    comparison_set = set()

    for i in range(len(sudoku_options)):
        if i != check_index:
            comparison_set.update(list(sudoku_options[i]))
    for S in sudoku_options:
        for item in S:
            if not item in comparison_set:
                return item
    return -1

以下是简单的测试代码:

if __name__ == "__main__":
    row1 = [{1}, {3}, {5}, {6}, {8}, {9}, {4,7}, {4,7}, {2,4,7}]
    x = find_unique(row1, 8)
    print(x)
    #Output: 2 (as desired)

感谢您的所有帮助!

5 个答案:

答案 0 :(得分:1)

我建议使用defaultdict,并为每个值保留它所属的集合的列表。然后找到属于一组的元素。

from collections import defaultdict
import typing

def find_sets_with_unique_elements(set_list: typing.List[typing.Set]):
    counter = defaultdict(list)
    for i, el in enumerate(set_list):
        for val in el:
            counter[val].append(i)
    return [(sets[0], val) for val, sets in counter.items() if len(sets) == 1]

if __name__ == "__main__":
    row1 = [{1}, {3}, {5}, {6}, {8}, {9}, {4,7}, {4,7}, {2,4,7}]
    x = find_sets_with_unique_elements(row1)
    print(x)

答案 1 :(得分:0)

您可以通过以下方法使其更简单:

# Note that this returns a set of all unique elements.
# Getting all of the numbers keeps you from calling
# the function multiple times until you get a -1
# instead of iterating through the set that's returned.

def find_unique(check, *other):
    # `check` is the set to find a unique element from
    # `*other` is the tuple of sets to compare against

    check = check.copy() # Get a copy

    for set_ in other:
        # This will remove an element that is in both
        # `check` and `set_` and will remove it from
        # `check`.
        check -= set_

        # Early exit condition (where `check` is empty)
        if not check:
            break

    return check

答案 2 :(得分:0)

假设您最初的想法是从目标位置中的集合中返回 first 唯一项(如您的初始功能所示):

def find_unique(sudoku_options, check_index):
    if check_index >= len(sudoku_options):
        raise IndexError(f'Index {check_index} is out of range')
    lst_copy = sudoku_options.copy()
    lst_copy.pop(check_index)   # exclude target set from list copy

    for num in sudoku_options[check_index]:
        if num not in set.union(*lst_copy):
            return num
    return -1

row1 = [{1}, {3}, {5}, {6}, {8}, {9}, {4,6}, {4,6}, {2,4,6}]
x = find_unique(row1, 8)
print(x)   # 2
x = find_unique(row1, 4)
print(x)   # 8
x = find_unique(row1, 3)
print(x)   # -1

答案 3 :(得分:0)

那么,可以实现2倍的增强,如下所示:

In [19]: row1[8].difference(reduce(lambda x, y: x.union(y), row1[:8], set() ))                  
Out[19]: {2}

In [20]: %timeit row1[8].difference(reduce(lambda x, y: x.union(y), row1[:8], set() ))          
4.7 µs ± 105 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [21]: %timeit find_unique(row1, 8)                                                           
8.32 µs ± 71 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

编辑:删除了不必要的reduce:D,实现了约6倍增强

In [9]: %timeit row1[8].difference(set.union(*row1[:8]))                                        
1.42 µs ± 109 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

答案 4 :(得分:0)

不确定是不是您要找的东西

def find_unique(sudoku_options, check_index):
    sets_to_check = sudoku_options[:]
    check_set = sets_to_check.pop(check_index)

    all_numbers = set().union(*sets_to_check)
    return check_set - all_numbers

if __name__ == "__main__":
    row1 = [{1}, {3}, {5}, {6}, {8}, {9}, {4,7}, {4,7}, {2,4,7}]
    x = find_unique(row1, 8)
    for number in x:
        print(number)