3

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

>>> 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
4

12 回答 12

11

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

def has1dup(lst):
    return len(lst)-1 == len(set(lst))
于 2012-04-27T01:04:22.550 回答
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

适用于 Python 2.7+的Counter作品,对于较低版本,您可以手动完成

def counter(seq): 
    r = {}
    for x in seq:
        r[x] = r.setdefault(x, 0) + 1 # or defaultdict
    return r
于 2012-04-27T01:15:48.287 回答
2

您可以使用内置any()非常轻松且很好地做到这一点:

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
于 2012-04-27T01:15:48.340 回答
1
2 in collections.Counter(yourList).values()

简短而高效。

如果您的意思是“完全”,如“在元素的多重性中,恰好有一个元素的多重性为 2”,那么您可以:

Counter(Counter(yourList).values()).get(2)==1
于 2012-04-27T01:16:44.933 回答
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 的呢?product 返回的对是每个元素与列表的第二个副本中的一个元素配对。如果所有 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
于 2012-04-27T02:23:44.133 回答
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

这是一个演示。

于 2012-04-27T01:03:38.853 回答
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

于 2012-04-27T01:04:43.143 回答
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
于 2012-04-27T01:05:30.990 回答
0

如果只有一个/没有一个元素重复,并且您可以将元素表示为正整数(例如通过使用字典将“一”映射到 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
于 2012-04-27T01:21:23.230 回答
0
def exactlyTwo(elements):
    return sum(elements.count(i)-1 for i in elements) == 2

适用于不可散列的元素,其中“正好两个元素”表示三元组和两个双打应该返回 False

于 2012-04-28T14:28:47.377 回答
-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
于 2012-04-27T01:05:58.180 回答
-2

你可以试试

list(["one", "one", "two"]).count("one") == 2
于 2012-04-27T01:01:42.460 回答