有效地确定列表中的三个项目中的两个是否相同

时间:2012-04-27 00:59:59

标签: python algorithm list

确定列表中两个元素是否完全相同的最有效方法是什么?例如:

>>> has1dup(["one", "one", "two"])
True
>>> has1dup(["one", "two", "three"])
False
>>> has1dup(["one", "one", "one"])
False

我使用if / else语句成功完成了此操作。但是,如果列表较大,则为一对写出每种可能性的任务将变得非常困难和耗时。是否有更快/更简单的方法来实现这一目标?

以下是我的尝试:

def has1dup(lst):
    if lst[0] == lst[1] and lst[1] != lst[2]:
        return True
    elif lst[1] == lst[2] and lst[2] != lst[0]:
        return True
    elif lst[0] == lst[2] and lst[2] != lst[1]:
        return True
    else:
        return False

12 个答案:

答案 0 :(得分:11)

您可以看到set有多少个唯一值。如果集合中的项目少于列表中的项目,则一个项目是重复项目:

def has1dup(lst):
    return len(lst)-1 == len(set(lst))

答案 1 :(得分:3)

>>> from collection import Counter
>>> 2 in Counter(["one", "one", "two"]).values()
True
>>> 2 in Counter(["one", "two", "three"]).values()
False

更新
如果你想要只有两个相同的项目

Counter(seq).values().count(2) == 1

Counter适用于Python 2.7+,对于较低版本,您可以手动执行

def counter(seq): 
    r = {}
    for x in seq:
        r[x] = r.setdefault(x, 0) + 1 # or defaultdict
    return r

答案 2 :(得分:2)

您可以使用the any() builtin非常轻松地完成此操作:

def has_duplicates(seq):
    return any(seq.count(x) > 1 for x in seq)

示例:

>>> has_duplicates([1, 1, 2])
True
>>> has_duplicates([1, 2, 2])
True
>>> has_duplicates([1, 2, 3])
False

如果您只想查找两个且仅两个项目相同的位置,只需更改条件:

any(seq.count(x) == 2 for x in seq)

如果你想找到哪一个,只有一个实例,只有两个项目,我们也可以这样做,虽然它需要更多的工作:

def any_n(iterable, n):
    seen = 0
    for value in iterable:
        if value:
            if seen >= n:
                return False
            else:
                seen += 1
    return seen == n

def has_one_value_repeated_n_times(seq, n):
    return any_n((seq.count(x) == n for x in seq), n)

一些快速测试:

tests = [
    [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5],
    [1,2,2,3,3,4,4,4,4,5,5,5,5,5],
    [1,2,2],
    [1,1,2],
    [1,2,3],
]

for test in tests:
    print(test, "-", has_one_value_repeated_n_times(test, 2))

给我们:

[1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5] - True
[1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5] - False
[1, 2, 2] - True
[1, 1, 2] - True
[1, 2, 3] - False

答案 3 :(得分:1)

2 in collections.Counter(yourList).values()

简短而有效。

如果你的意思是“完全”,如“在多个元素中,只有一个元素具有多重性2”,那么你可以这样做:

Counter(Counter(yourList).values()).get(2)==1

答案 4 :(得分:0)

我不懂Python,但这里有一些伪代码:

for i in 0 to length(list):
    j = indexOf(list, list[i], i + 1) > -1

    if j > -1 and indexOf(list, list[i], j + 1) == -1:
        // Found exactly two!

它应该足以满足您的需求。

编辑:好的,我把它变成了Python。对不起,如果这不是好代码。

def exactlyTwo(l):
    for i in xrange(0, len(l)):
        try:
            j = l.index(l[i], i + 1)

            try:
                l.index(l[i], j + 1)
            except ValueError:
                return True
        except ValueError:
            # Do nothing. Not sure how to do that in Python.
            0

    return False

Here's a demo.

答案 5 :(得分:0)

我试试这个:len(set(my_list)) == 2

但后来我发现在这种情况下(3项),我们可以做得更好: > python -c 'from timeit import Timer; t1 = Timer("a[0] == a[1] != a[2] or a[0] == a[2] != a[1] or a[1] == a[2] != a[0]", setup="""a=["one","one","two"]"""); t2 = Timer("len(set(a)) == 2", setup="""a=["one","one","two"]"""); print t1.timeit(), t2.timeit()'

0.893960952759 2.28438997269

答案 6 :(得分:0)

你拥有的代码没有任何问题(至少对于大小为3的列表) - 它可读且相当简洁,你应该只关心性能如果它成为一个问题。

像集合转换这样的解决方案比三个条件快得多的可能性虽然不是不可能,但不太可能。

我更喜欢稍微不同的形式来减少“缩进地狱”: - )

if list[0] == list[1] and list[1] != list[2]:
    return True

if list[1] == list[2] and list[2] != list[0]:
    return True

if list[0] == list[2] and list[2] != list[1]:
    return True

return False

或者,如果您希望在屏幕/打印输出上同时看到尽可能多的代码:

if list[0] == list[1] and list[1] != list[2]: return True
if list[1] == list[2] and list[2] != list[0]: return True
if list[0] == list[2] and list[2] != list[1]: return True
return False

对于较大的数组,可以将其转换为集合,如果集合的长度小于数组的长度,则只有一个重复:

>>> a = [1,2,3,4,4,5,6,7]
>>> a
[1, 2, 3, 4, 4, 5, 6, 7]
>>> len(a) == len (set(a)) + 1
True

答案 7 :(得分:0)

如果只重复一个/没有元素,你可以将元素表示为正整数(比如通过使用dict将“one”映射到1)

然后以下解决方案将起作用

def find_repeated_element(l):
    return reduce(lambda x,y: x^y, l + list(set(l)))

l = [1,1,2]
>>> find_repeated_element(l)
1
l = [1,2,3]
>>> find_repeated_element(l)
0
l = [1,1,1]
>>> find_repeated_element(l)
0

答案 8 :(得分:0)

由于我们需要进行成对比较,如何使用itertools.product创建所有对比较的序列?

from itertools import product

tests = """\
AAB
ABC
ABB
ABA
AAA""".splitlines()

def has_exactly_one_doubled_element(t):
    return sum(map(lambda a:a[0]==a[1], product(t,t))) == 5

for t in tests:
    print t, has_exactly_one_doubled_element(t)

打印:

AAB True
ABC False
ABB True
ABA True
AAA False

那么,我怎么想出5的幻数?产品返回的对是每个元素与列表的第二个副本中的元素配对。如果所有3都是不同的,那么它们每个都将比较等于它们自己而不是其他,所以总数将是3.如果2相同,那么除了3个匹配之外,两个重复将比较相等于一次在每个方向上,所以加2到3得到5.如果所有3都相同,则每个元素将与其他所有元素匹配,用于3 * 3或9个匹配。

以下是任意长度列表的一般解决方案,以查看是否只有一个重复值(也使用operator.__eq__itertools.starmap来避免将lambda传递给map) :

from operator import __eq__ as EQ
from itertools import product, starmap

def has_exactly_one_doubled_element(t):
    return sum(starmap(EQ, product(t,t))) == len(t)+2

args = ["ABCD"]*4
tests = map(''.join, product(*args))
for t in tests:
    print t, has_exactly_one_doubled_element(t)

打印:

AAAA False
AAAB False
AAAC False
AAAD False
AABA False
AABB False
AABC True
AABD True
AACA False
AACB True
AACC False
AACD True
AADA False
AADB True
AADC True
AADD False
ABAA False
ABAB False
ABAC True
ABAD True
ABBA False
ABBB False
ABBC True
ABBD True
ABCA True
ABCB True
ABCC True
ABCD False
ABDA True
ABDB True
ABDC False
ABDD True
ACAA False
ACAB True
ACAC False
ACAD True
ACBA True
ACBB True
ACBC True
ACBD False
ACCA False
ACCB True
ACCC False
ACCD True
ACDA True
ACDB False
ACDC True
ACDD True
ADAA False
ADAB True
ADAC True
ADAD False
ADBA True
ADBB True
ADBC False
ADBD True
ADCA True
ADCB False
ADCC True
ADCD True
ADDA False
ADDB True
ADDC True
ADDD False
BAAA False
BAAB False
BAAC True
BAAD True
BABA False
BABB False
BABC True
BABD True
BACA True
BACB True
BACC True
BACD False
BADA True
BADB True
BADC False
BADD True
BBAA False
BBAB False
BBAC True
BBAD True
BBBA False
BBBB False
BBBC False
BBBD False
BBCA True
BBCB False
BBCC False
BBCD True
BBDA True
BBDB False
BBDC True
BBDD False
BCAA True
BCAB True
BCAC True
BCAD False
BCBA True
BCBB False
BCBC False
BCBD True
BCCA True
BCCB False
BCCC False
BCCD True
BCDA False
BCDB True
BCDC True
BCDD True
BDAA True
BDAB True
BDAC False
BDAD True
BDBA True
BDBB False
BDBC True
BDBD False
BDCA False
BDCB True
BDCC True
BDCD True
BDDA True
BDDB False
BDDC True
BDDD False
CAAA False
CAAB True
CAAC False
CAAD True
CABA True
CABB True
CABC True
CABD False
CACA False
CACB True
CACC False
CACD True
CADA True
CADB False
CADC True
CADD True
CBAA True
CBAB True
CBAC True
CBAD False
CBBA True
CBBB False
CBBC False
CBBD True
CBCA True
CBCB False
CBCC False
CBCD True
CBDA False
CBDB True
CBDC True
CBDD True
CCAA False
CCAB True
CCAC False
CCAD True
CCBA True
CCBB False
CCBC False
CCBD True
CCCA False
CCCB False
CCCC False
CCCD False
CCDA True
CCDB True
CCDC False
CCDD False
CDAA True
CDAB False
CDAC True
CDAD True
CDBA False
CDBB True
CDBC True
CDBD True
CDCA True
CDCB True
CDCC False
CDCD False
CDDA True
CDDB True
CDDC False
CDDD False
DAAA False
DAAB True
DAAC True
DAAD False
DABA True
DABB True
DABC False
DABD True
DACA True
DACB False
DACC True
DACD True
DADA False
DADB True
DADC True
DADD False
DBAA True
DBAB True
DBAC False
DBAD True
DBBA True
DBBB False
DBBC True
DBBD False
DBCA False
DBCB True
DBCC True
DBCD True
DBDA True
DBDB False
DBDC True
DBDD False
DCAA True
DCAB False
DCAC True
DCAD True
DCBA False
DCBB True
DCBC True
DCBD True
DCCA True
DCCB True
DCCC False
DCCD False
DCDA True
DCDB True
DCDC False
DCDD False
DDAA False
DDAB True
DDAC True
DDAD False
DDBA True
DDBB False
DDBC True
DDBD False
DDCA True
DDCB True
DDCC False
DDCD False
DDDA False
DDDB False
DDDC False
DDDD False

答案 9 :(得分:0)

def exactlyTwo(elements):
    return sum(elements.count(i)-1 for i in elements) == 2

适用于不可用的元素,以及恰好两个元素的位置'意味着三胞胎,两个双打应该返回False

答案 10 :(得分:-1)

def checkk(lis):
  sett=set(lis)
  for ele in sett:
     if lis.count(ele)==2:
       return 'yes'
  else:
     return 'no'


x=list(["one", "one", "two"])
y=list(["one", "two", "three"])
z=list(["one", "one", "one"])
w=list(["one", "two", "two"])
print(checkk(x))
print(checkk(y))
print(checkk(z))
print(checkk(w))

<强>输出:

yes
no
no
yes

答案 11 :(得分:-2)

你可以尝试

list(["one", "one", "two"]).count("one") == 2