简体   繁体   English

确保子列表中只有一个成员存在于Python列表中

[英]Ensure a only single member of a sublist is present in a Python list

Let's say I have a Python list that might contain any combination of members from the following two tuples: 假设我有一个Python列表,其中可能包含来自以下两个元组的成员的任意组合:

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

So legal combination lists would include 因此合法组合清单将包括

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

Any length, any combination. 任何长度,任何组合。 You can assume no duplicated characters will be in the combination list though. 您可以假定组合列表中没有重复的字符。 I'd like to apply a function to those combinations that modifies them (in place) such that they contain at most a single member of one of the tuples -- say it's numbers. 我想将一个函数应用于那些修改它们的组合(就地),以使它们最多包含一个元组的单个成员-就是数字。 The 'chosen' member of the number tuple should be selected at random. 数字元组的“选择”成员应随机选择。 I also don't care if order gets mangled in the process. 我也不在乎订单是否在此过程中受到破坏。

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

I can't think of any one-liner to solve this, but I believe this is concise enough. 我想不出任何一种解决方案,但是我相信这很简洁。

    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

In case you don't instantly see the need for the exception handling, we need to catch the IndexError that would result from trying to pass an empty list to random.choice(). 如果您没有立即看到需要进行异常处理,则需要捕获因尝试将空列表传递给random.choice()而导致的IndexError。

Not the best, but it should work 不是最好的,但应该可以

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

Maybe This? 也许这个?

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

Disclaimer: I'm a python beginner myself, so there might be a better way, but this is how I would do it : 免责声明:我本人是python初学者,所以可能会有更好的方法,但这就是我的方法:

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]

Note that I shuffle the list since you said you wanted to keep a random element. 请注意,由于您说过要保留随机元素,因此我对列表进行了混洗。 The iteration is done backwards to keep the correct indices after elements have been deleted from the list. 从列表中删除元素后,将向后进行迭代以保留正确的索引。

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

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