确保Python列表中只存在子列表的单个成员

时间:2015-06-04 23:26:53

标签: python list set membership

假设我有一个Python列表,其中可能包含以下两个元组的成员组合:

legal_letters = ('a', 'b', 'c')
legal_numbers = (1, 2, 3)

所以合法的组合清单包括

combo1 = ['a', 1, '3']
combo2 = ['c']
combo3 = ['b', 2, 1, 'c']

任何长度,任何组合。您可以假设组合列表中没有重复的字符。我想将一个函数应用于那些修改它们的组合(就地),这样它们最多只包含一个元组的一个成员 - 比如它的数字。应该随机选择数字元组的“选定”成员。如果订单在这个过程中被破坏,我也不在乎。

def ensure_at_most_one_number(combo):
 # My first attempts involved set math and a while loop that was 
 # pretty gross, I'll spare you guys the details.  I'm sure I could get it to work
 # but I figured there might be a one-liner or some fancy itertools out there
 return combo


# Post transformation
combo1 = ['a', '1']
combo2 = ['c']
combo3 = ['c', 'b', 2] # Mangled order, not a problem

4 个答案:

答案 0 :(得分:1)

我想不出任何 one-liner 来解决这个问题,但我相信这很简洁。

    def only_one_number(combo):
        import random

        try:
            number = random.choice([x for x in combo if x in legal_numbers])
            combo[:] = [x for x in combo if x in legal_letters]
            combo.append(number)
        except IndexError:
            pass

如果您没有立即看到需要进行异常处理,我们需要捕获因尝试将空列表传递给random.choice()而导致的IndexError。

答案 1 :(得分:0)

不是最好的,但应该有效

numbers = []
for i in legal_numbers:
  if i in combo:
    numbers.append(i)
    combo.remove(i)
if len(numbers) == 0:
  return combo
combo.append(random.choice(numbers))
return combo

答案 2 :(得分:0)

也许这个?

def ensure_at_most_one_number(combo):
    i = len(combo) - 1      # start with the last element
    found_number = False

    while i >= 0:
        try:
            int(combo[i])   # check element is a number
            if  found_number == True:
                del combo[i]    # remove it if a number already found
            else:
                found_number = True
        except ValueError:
            pass             # skip element if not a number
        i -= 1

    return combo

答案 3 :(得分:0)

免责声明:我自己是一名初学者,所以可能有更好的方法,但这就是我要做的事情:

import random

def ensure_at_most_one_number(combo, legal_numbers) :

    random.shuffle(combo)
    first_number = True

    for i in range(len(combo)-1, -1, -1) :
        if combo[i] in legal_numbers :
            if first_number :
                first_number = False
            else :
                del combo[i]

请注意,因为您说要保留随机元素,所以我会对列表进行随机播放。迭代完成后,在从列表中删除元素后保留正确的索引。