Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/213.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python3查找两个列表中的差异,以使其相等_Python_Python 3.x_List_Multiset - Fatal编程技术网

Python3查找两个列表中的差异,以使其相等

Python3查找两个列表中的差异,以使其相等,python,python-3.x,list,multiset,Python,Python 3.x,List,Multiset,假设我们有两个列表,始终具有相同的长度,始终包含字符串 list1 = ['sot', 'sot', 'ts', 'gg', 'gg', 'gg'] list2 = ['gg', 'gg', 'gg', 'gg', 'gg', 'sot'] 我们需要找到: 列表2应更改多少项才能与列表1相等 因此,在前面的示例中,它应该返回2 对于此示例: list1 = ['sot', 'sot', 'ts', 'gg', 'gg', 'gg'] list2 = ['gg', 'gg', 'gg', 'gg

假设我们有两个列表,始终具有相同的长度,始终包含字符串

list1 = ['sot', 'sot', 'ts', 'gg', 'gg', 'gg']
list2 = ['gg', 'gg', 'gg', 'gg', 'gg', 'sot']
我们需要找到:

列表2应更改多少项才能与列表1相等

因此,在前面的示例中,它应该返回
2

对于此示例:

list1 = ['sot', 'sot', 'ts', 'gg', 'gg', 'gg']
list2 = ['gg', 'gg', 'gg', 'gg', 'sot', 'sot']
list1 = ['sot', 'sot', 'ts', 'gg', 'gg', 'gg']
list2 = ['ts', 'ts', 'ts', 'ts', 'ts', 'ts']
它应该返回
1

最后,对于这个例子:

list1 = ['sot', 'sot', 'ts', 'gg', 'gg', 'gg']
list2 = ['gg', 'gg', 'gg', 'gg', 'sot', 'sot']
list1 = ['sot', 'sot', 'ts', 'gg', 'gg', 'gg']
list2 = ['ts', 'ts', 'ts', 'ts', 'ts', 'ts']
它应该返回
5

我们不关心哪些元素应该变成什么。我们都不关心订单,所以这意味着

['gg', 'gg', 'gg', 'gg', 'gg', 'sot'] 
and
['gg', 'gg', 'sot', 'gg', 'gg', 'gg']
值相等,且它们的结果应为0

列表的长度可以是6、8、20或其他任何长度,有时会有更多的元素


我尝试了很多东西,比如
set(list1)-set(list2)
list(set(list1).difference(list2))
set(list1).symmetric_difference(set(list2))
,但都没有成功。

你可以使用
集合。计数器
来计算两个列表中的项目数,把它们区别开来

from collections import Counter
def func(list1, list2):
    #Convert both list to counters, and subtract them
    c = Counter(list1) - Counter(list2)

    #Sum up all values in the new counter
    return sum(c.values())
输出为

list1 = ['sot', 'sot', 'ts', 'gg', 'gg', 'gg']
list2 = ['gg', 'gg', 'gg', 'gg', 'gg', 'sot']
print(func(list1, list2))
#2

list1 = ['sot', 'sot', 'ts', 'gg', 'gg', 'gg']
list2 = ['gg', 'gg', 'gg', 'gg', 'sot', 'sot']
print(func(list1, list2))
#1

list1 = ['sot', 'sot', 'ts', 'gg', 'gg', 'gg']
list2 = ['ts', 'ts', 'ts', 'ts', 'ts', 'ts']
print(func(list1, list2))
#5

如果某个项目的数量不同,则使用
set
会导致问题。相反,使用。如其他答案中所述,您可以为两个列表创建一个
计数器
,然后使用
-
获得它们之间的差异,并获得
值的
。 但是,请注意,这仅在列表大小相同时才起作用。如果列表中的元素数量不相同,则根据从哪个列表中减去哪个列表,您将获得不同数量的发散元素

另一方面,使用
减法
,您将得到两个方向的差异,对“太多”的项目使用正数,对“太少”项目使用负数。这意味着,您可能必须将结果除以2,即,
sum(…)/2
,但对于大小不同的列表,它应该更有效

>>> list1 = ['sot', 'sot', 'ts', 'gg', 'gg', 'gg']
>>> list2 = ['gg', 'gg', 'gg', 'gg', 'sot', 'sot']
>>> c = Counter(list1)
>>> c.subtract(Counter(list2))
# Counter({'gg': -1, 'sot': 0, 'ts': 1})
>>> sum(map(abs, c.values()))
2
另一种可能也适用于不同大小的列表,即使用
&
获取公共元素,并将其与较大列表中的元素总数进行比较:


您可以利用以下多种可能性:


让我们检查一下其他示例:

list1 = ['sot', 'sot', 'ts', 'gg', 'gg', 'gg']
list2 = ['gg', 'gg', 'gg', 'gg', 'sot', 'sot']

sum((Counter(list1) - Counter(list2)).values())
# 1

list1 = ['sot', 'sot', 'ts', 'gg', 'gg', 'gg']
list2 = ['ts', 'ts', 'ts', 'ts', 'ts', 'ts']

sum((Counter(list1) - Counter(list2)).values())
# 5

list1 = ['gg', 'gg', 'gg', 'gg', 'gg', 'sot'] 
list2 = ['gg', 'gg', 'sot', 'gg', 'gg', 'gg']

sum((Counter(list1) - Counter(list2)).values())
# 0

细节

通过使用
计数器
,您将以字典的形式对每个列表中的所有元素进行计数。让我们回到第一个示例:

c1 = Counter(list1)
# Counter({'sot': 2, 'ts': 1, 'gg': 3})

c2 = Counter(list2)
# Counter({'gg': 5, 'sot': 1})
现在我们想了解一下:

  • 哪些项目出现在
    list1
    中,而不在
    list2

  • 在存在和不存在的列表中,还需要多少个列表2才能使它们包含相同数量的计数

我们可以利用计数器支持数学运算的事实,其结果产生
多集
,即计数器的计数大于零。因此,考虑到我们正在寻找两个计数器之间的差异,我们似乎可以减去它们,看看在
list2
中需要哪些元素及其各自的计数

那么计数器之间的减法是如何工作的呢?让我们用一个简单的例子进行检查:

Counter({1:4, 2: 1}) - Counter({1:1, 3:1})  
# Counter({1: 3, 2: 1})
这样做是减去相应元素的计数,所以第一个计数器中包含的元素,所以这里的顺序很重要。因此,回到提议的示例,减去两个列表将产生:

 sub = Counter(list1) - Counter(list2)
# Counter({'sot': 1, 'ts': 1})
现在,我们只需计算所有
键中的
,这可以通过以下方法完成:

sum(sub.values())
# 2

你不是在这里谈论清单。您的问题是,因为顺序并不重要,但您需要知道每种类型的值有多少。多集有时称为包或多集

Python标准库有一个multiset实现:,它将唯一元素映射到一个计数。请在此处使用:

from collections import Counter

mset1 = Counter(list1)
mset2 = Counter(list2)

# sum the total number of elements that are different between
# the two multisets
sum((mset1 - mset2).values())
将一个计数器与另一个计数器相减,将得到第一个多集合中但不在另一个多集合中的所有元素的多集合,
sum(mset.values())
相加为元素总数

因为输入总是相同的长度,您只需要知道有多少个元素是不同的,所以按哪个顺序减去多重集并不重要。您将始终得到正确的答案,
sum((mset1-mset2).values())
sum((mset2-mset1).values())
将始终生成完全相同的数字

这是因为两个多重集合都有N个元素,其中K个元素不同。因此,两个多集都将有K个不在另一个多集中的额外元素,并且有K个缺失元素存在于另一个多集中<代码>-
减法将为您提供第一组中缺少的K个额外元素

将其放入函数:

def mset_diff(iterable1, iterable2):
    return sum((Counter(iterable1) - Counter(iterable2)).values())
并应用于您的输入:

>>> mset_diff(['sot', 'sot', 'ts', 'gg', 'gg', 'gg'], ['gg', 'gg', 'gg', 'gg', 'gg', 'sot'])
2
>>> mset_diff(['sot', 'sot', 'ts', 'gg', 'gg', 'gg'], ['gg', 'gg', 'gg', 'gg', 'sot', 'sot'])
1
>>> mset_diff(['sot', 'sot', 'ts', 'gg', 'gg', 'gg'], ['ts', 'ts', 'ts', 'ts', 'ts', 'ts'])
5

Counter()
类是
dict
的一个子类,计算元素的速度快且效率高,两个元素之间的差值的计算在O(N)线性时间内完成。

因此,顺序无关紧要?您不能使用
set
,因为
set
只包含唯一的值。根据Python用于列表相等的规则,
list2
等于
list1
的值是4,而不是2。你说的是集合,而不是列表。特别是关于多集。您不想使用
subtract()
,因为这样您总是会得到0。两个多重集具有相同的元素数(N),因此两个计数器具有相同的总值。如果使用
减法
,则结果始终为零,因为其中一个元素的剩余部分为正计数,另一个元素的剩余部分为负计数,这将始终是相同的数字