【问题标题】:Python - Converting long list of addresses into list of strings and intersection of listsPython - 将长地址列表转换为字符串列表和列表的交集
【发布时间】:2014-05-03 23:41:25
【问题描述】:

我有两个非常长的文本文件(数千个电子邮件地址,每行一个),我正在寻找一种方法来比较这两个文件并输出包含在第一个文件和第二个文件,但不在两个文件中(类似于集合论中的 AUB/(A⋂B) )。如果我可以使用包含字符串的列表作为输入,那就很容易了,就像这样

input1=['address1','address2',...,'addressn']

但是由于我的文本文件很长并且在不同的行上,我应该手动将每个地址放在“”中。所以我尝试使用一个字符串,所有地址用空格分隔作为输入,然后将其转换为字符串列表。这就是我得出的结论:

import numpy as np
from StringIO import StringIO

def conv(data):
    array1=np.genfromtxt(StringIO(data),dtype="|S50")
    lista1=[]
    for el in array1:
        lista1.append(el)
    return lista1

input1='address1 address2 ... addressn'

这就是我调用函数时得到的结果

>conv(input1)
>['address1', 'address2', 'addressn']

它有效,但我有一个问题:输入必须是水平的,所以我不能从文本文件中复制我的地址并将它们粘贴到一个字符串中,因为我会得到类似的东西

input1="Davide
...:Michele
...:Giorgio
...:Paolo"

File "<ipython-input-4-6d70053fb94e>", line 1
  input1="Davide
             ^
SyntaxError: EOL while scanning string literal

我该如何处理这个问题?任何改进代码的建议都会非常感激。我对 StringIO 模块几乎一无所知,我今天第一次遇到它,而且我确信它可以编写一个比我的更高效的程序。顺便说一下,这是整个程序:

def scan(data1,data2): #Strings
    array1=np.genfromtxt(StringIO(data1),dtype="|S50")
    array2=np.genfromtxt(StringIO(data2),dtype="|S50")
    lista1=[]
    lista2=[]
    for el in array1:
        lista1.append(el)
    for el in array2:
        lista2.append(el) #lista1 and lista2 are lists containing strings
    num1,num2=len(lista1),len(lista2)
    shared=[]
    for el in lista1:
        if el in lista2:
            shared.append(el) #shared is the intersection of lista1 and lista2
    if len(shared)==0:
        print 'No shared elements'
        return lista1+lista2
    else:
        for el in shared:
            n1=lista1.count(el)
            for i in range(n1):
                lista1.remove(el) #Removes from lista1 the elements shared with lista2
            n2=lista2.count(el)   #as many times as they appear
            for j in range(n2):
                lista2.remove(el) #Removes from lista2 the elements shared with lista1
    result=lista1+lista2          #as many times as they appear
    print 'Addresses list 1:',num1
    print 'Addresses list 2:',num2
    print 'Useful Addresses:',len(list(set(result)))
    return (list(set(result)))

这是它如何工作的一个例子:

data1="Davide John Kate Mary Susan"
data2="John Alice Clara Kate John Alex"
scan(data1,data2)
>Addresses list 1: 5
>Addresses list 2: 6
>Useful Addresses: 6
>['Alex', 'Susan', 'Clara', 'Alice', 'Mary', 'Davide']

感谢您的帮助:)

【问题讨论】:

  • 我想使用集合 docs.python.org/2/library/sets.html 会很有用
  • 但我认为使用集合(定义为 unique 元素的无序集合)可能存在问题:我可能在每个起始列表中都有重复项。
  • 需要重复吗?
  • 不,我刚刚意识到 Sets 会自动删除重复项,效果很好。这是一个非常有用的模块,我不知道,非常感谢。
  • 你应该知道你只能接受一个答案:)

标签: python stringio genfromtxt


【解决方案1】:

在跨越多行的字符串周围使用三引号:

input1="""Davide
...:Michele
...:Giorgio
...:Paolo"""

然后它们将由返回 ("\n") 分隔,因此您可以使用 inpu1.split('\n') 将其转换为列表。

使用集合对象,您的操作变得非常简单。要获取s1 中不在s2 中的元素,我们可以简单地执行s1 - s2。联合只是|,交集只是&amp;,所以我们都知道了。

s1 = set(input1.split('\n'))
s2 = set(input2.split('\n'))
adresses_in_only_one_file = (s1 | s2) - (s1 & s2)

【讨论】:

  • 谢谢,三引号和 .split('\n') 是我想要的。有趣的是,你在三行中做了我近 30 行所做的事情。谢谢!
【解决方案2】:

扩展 @irh 的答案,然后您可以使用 sets 获得两组之间的对称差异:(list1 和 list2 中的元素,但不是两者中的元素)

list1 = ['address1', 'address2', 'address3']

list1 = ['address5', 'address4', 'address3']

result = list(set(list1) ^ set(list2))

>>> print result
['address1', 'address2', 'address4', 'address5']     #note result might be jumbled but that shouldn't matter

【讨论】:

  • 结果乱码其实没问题。对称差异很有用,谢谢。现在我正在查看所有的 Sets 函数。
  • @DavideL,Python 有很多强大的工具。真的有助于了解他们。玩得开心。
【解决方案3】:
shared =[]
for el in lista1:
    if el in lista2:
        shared.append(el) #shared is the intersection of lista1 and lista2

In [10]: lista1=[1,2,3,4,5,6,7,8,9]

In [11]: lista2=[1,2,3,10,11,12,13]

In [12]: lista1=set(lista1)

In [13]: shared = lista1.intersection(lista2) # same as your loop above

In [14]: shared
Out[14]: {1, 2, 3}

如果你想要一个列表,只需使用list(lista1.intersection(lista2))

for el in shared:
    n1=lista1.count(el)
    for i in range(n1):
        lista1.remove(el) #Removes from lista1 the elements shared with lista2
    n2=lista2.count(el)   #as many times as they appear
    for j in range(n2):
        lista2.remove(el)
result=lista1+lista2

         lista1=set(lista1) 
In [15]: list(lista1.symmetric_difference(lista2))
Out[15]: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13] # same as above.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-30
    • 2017-11-15
    • 1970-01-01
    • 2016-08-10
    • 2014-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多