简体   繁体   English

比较和迭代两个 2D arrays

[英]Compare and iterate over two 2D arrays

I have two 2D arrays like these:我有两个像这样的二维 arrays:

mix = [[1,'Blue'],[2,'Black'],[3,'Black'],[4,'Red']]

possibilities = [[1,'Black'],[1,'Red'],[1,'Blue'],[1,'Yellow'],
         [2,'Green'],[2,'Black'],
         [3,'Black'],[3,'Pink'],
         [4,'White'],[4,'Blue'],[4,'Yellow'],
         [5,'Purple'],[5,'Blue']
        ]

I want to loop through the possibilities list, find the exact index in which it matches the mix list, then append the correct mix into a new list.我想遍历可能性列表,找到它与混合列表匹配的确切索引,然后将 append 正确混合到一个新列表中。 IF it does not match the MIX list, append into a "bad list" and then move on to the next iteration.如果它与 MIX 列表不匹配,则 append 进入“坏列表”,然后继续进行下一次迭代。 For now this is the idea I had ---- note it totally DOES NOT work: :)现在这是我的想法----注意它完全不起作用::)

i = 0
j = 0
bad_guess = []
correct_guess = []
while i < len(mix):
    while possibilities[j] != mix[i]:
        j += 1
    if possibilities[j] == mix[i]:
        i +=1
        correct_guess.append(possibilities[j])
        j = 0
    elif possibilities[j] != mix[i]:
        bad_guess.append(mix[i])
        break

Output Basically the output I would want for this example is: Output基本上我想要这个例子的 output 是:

correct_guess = [[1,'Blue'],[2,'Black'],[3,'Black'],[5,'Purple']
bad_guess = [4,'Red']

This should do the job:这应该做的工作:

mix = [[1,'Blue'],[2,'Black'],[3,'Black'],[4,'Red']]

possibilities = [[1,'Black'],[1,'Red'],[1,'Blue'],[1,'Yellow'],
         [2,'Green'],[2,'Black'],
         [3,'Black'],[3,'Pink'],
         [4,'White'],[4,'Blue'],[4,'Yellow'],
         [5,'Purple'],[5,'Blue']
        ]

bad_guess = []
correct_guess = []
for i in mix:
    if i in possibilities:
        correct_guess.append(i)
    else:
        bad_guess.append(i)

There are a number of ways of solving this.有很多方法可以解决这个问题。 The simple way is to loop through the lists, but that's not very pythonic.简单的方法是遍历列表,但这不是很pythonic。 You can remove the inner loop using a containment check:您可以使用包含检查删除内部循环:

bad_guess = []
correct_guess = []
for item in mix:
    if item in possibilities:
        correct_guess.append(item)
    else:
        bad_guess.append(item)

The in operator is going to do a linear search through possibilities at every iteration. in运算符将在每次迭代中对possibilities进行线性搜索。 For a small list like this, it's probably fine, but for something larger, you will want a faster lookup.对于像这样的小列表,它可能很好,但对于更大的列表,您将需要更快的查找。

Faster lookup is offered in sets.成套提供更快的查找。 Unfortunately, sets can not contain non-hashable types such as lists.不幸的是,集合不能包含非散列类型,例如列表。 The good news is that they can contain tuples:好消息是它们可以包含元组:

mix = [tuple(item) for item in mix]
possibilities = {tuple(item) for item in possibilities}
bad_guess = []
correct_guess = []
for item in mix:
    if item in possibilities:
        correct_guess.append(item)
    else:
        bad_guess.append(item)

Another way to get the same result is to first sort mix by whether an item appears in possibilities or not, and then use itertools.groupby to create the output lists.获得相同结果的另一种方法是首先根据项目是否出现在possibilities中进行排序,然后使用itertools.groupby创建mix列表。 This approach is fun to parse, but is not particularly legible, and therefore not recommended:这种方法解析起来很有趣,但不是特别清晰,因此不推荐:

key = lambda item: item in possibilities
bad_guess, correct_guess = (list(g) for k, g in itertools.groupby(sorted(mix, key=key), key=key))

This last method is more algorithmically complex than the set lookup because sorting is an O(N log N) operation, while lookup in a set is O(1).最后一种方法在算法上比集合查找更复杂,因为排序是 O(N log N) 操作,而在集合中查找是 O(1)。

mix = {1:'Blue' , 2:'Black' , 3:'Black' , 4:'Red'}

possibilities = [[1,'Black'],[1,'Red'],[1,'Blue'],[1,'Yellow'],
     [2,'Green'],[2,'Black'],
     [3,'Black'],[3,'Pink'],
     [4,'White'],[4,'Blue'],[4,'Yellow'],
     [5,'Purple'],[5,'Blue']
    ]

for poss in possibilities:
    if (mix[poss[0]] = poss[1]) & (poss not in bad_guess):
        bad_guess.append(poss)
    elif poss not in good_guess:
        good_guess.append(poss)

you could try making the mix list a dictionary instead so you dont need to iterate over it您可以尝试将混合列表改为字典,这样您就不需要遍历它

As is often the case in Python , you don't actually have to muck about with indices at all to do this.正如在 Python 中经常出现的情况一样,您实际上根本不需要使用索引来执行此操作。

First, here is a simple solution using your existing data structure.首先,这是一个使用现有数据结构的简单解决方案。 Iterate over mix , and append each item to the appropriate list, depending on whether it's in possibilities or not.遍历mix和 append 每个项目到适当的列表,这取决于它是否有possibilities (This is the same idea presented in this answer to "How to split a list based on a condition?" ) (这与“如何根据条件拆分列表?”的答案中提出的想法相同)

mix = [
    [1, 'Blue'],
    [2, 'Black'],
    [3, 'Black'],
    [4, 'Red'],
]

possibilities = [
    [1, 'Black'], [1, 'Red'], [1, 'Blue'], [1, 'Yellow'],
    [2, 'Green'], [2, 'Black'],
    [3, 'Black'], [3, 'Pink'],
    [4, 'White'], [4, 'Blue'], [4, 'Yellow'],
    [5, 'Purple'], [5, 'Blue'],
]

correct_guesses = []
bad_guesses = []

for item in mix:
    if item in possibilities:
        correct_guesses.append(item)
    else:
        bad_guesses.append(item)

print(correct_guesses)
print(bad_guesses)

Output: Output:

[[1, 'Blue'], [2, 'Black'], [3, 'Black']]
[[4, 'Red']]

However, this does a lot of unnecessary looping.但是,这会产生很多不必要的循环。 Each time you check item in possibilities , the code has to iterate over possibilities (which is a list ) to see whether or not item is there.每次检查item in possibilities ,代码都必须遍历possibilities (这是一个列表)以查看item是否存在。

As others have commented, the issue here is your data structure.正如其他人评论的那样,这里的问题是您的数据结构。 Instead of a list, possibilities could be a dictionary . possibilities可以是字典,而不是列表。 Checking whether a dictionary has a given key, or accessing the value associated with a given key, is O(n);检查字典是否具有给定键,或访问与给定键关联的值是 O(n); essentially it's "instant" instead of having to go look for it.本质上它是“即时的”,而不必 go 寻找它。

possibilities = {
    1: ['Black', 'Red', 'Blue', 'Yellow'],
    2: ['Green', 'Black'],
    3: ['Black', 'Pink'],
    4: ['White', 'Blue', 'Yellow'],
    5: ['Purple', 'Blue']
}

Here each key is an integer, and each value is a list of the colors that number allows.这里每个键是一个 integer,每个值是该数字允许的 colors 的列表。 Then your for loop would look like this, checking if the color is one allowed for that number然后你的for循环看起来像这样,检查颜色是否是该数字允许的颜色

for item in mix:
    number, color = item
    if color in possibilities[number]:
        correct_guesses.append(item)
    else:
        bad_guesses.append(item)

Do you see the problem, though?不过,你看到问题了吗? We're still doing the same thing: using in on a list.我们仍在做同样的事情:在列表中使用in We could turn each of those lists into a set instead, which can much more efficiently check whether or not it contains something:我们可以将这些列表中的每一个变成一个集合,这样可以更有效地检查它是否包含某些内容:

possibilities = {
    1: {'Black', 'Red', 'Blue', 'Yellow'},
    2: {'Green', 'Black'},
    3: {'Black', 'Pink'},
    4: {'White', 'Blue', 'Yellow'},
    5: {'Purple', 'Blue'}
}

The for loop would remain the same. for循环将保持不变。


With all that in mind, here's a complete solution.考虑到所有这些,这里有一个完整的解决方案。 I've also changed the two-item lists to tuples , which serves no functional difference in this case, but is more idiomatic.我还将两项列表更改为tuples ,在这种情况下没有功能差异,但更惯用。

mix = [
    (1, 'Blue'),
    (2, 'Black'),
    (3, 'Black'),
    (4, 'Red'),
]

possibilities = {
    1: {'Black', 'Red', 'Blue', 'Yellow'},
    2: {'Green', 'Black'},
    3: {'Black', 'Pink'},
    4: {'White', 'Blue', 'Yellow'},
    5: {'Purple', 'Blue'}
}

correct_guesses = []
bad_guesses = []

for item in mix:
    number, color = item
    if color in possibilities[number]:
        correct_guesses.append(item)
    else:
        bad_guesses.append(item)

print(correct_guesses)
print(bad_guesses)

Output: Output:

[(1, 'Blue'), (2, 'Black'), (3, 'Black')]
[(4, 'Red')]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM