【问题标题】:Quickly eliminate "circular duplicates" in a big list (python)快速消除大列表中的“循环重复”(python)
【发布时间】:2020-06-10 04:26:52
【问题描述】:

我有这个 (python) 列表

my_list = [['dog','cat','mat','fun'],['bob','cat','pan','fun'],['dog','ben','mat ','老鼠'],
['cat','mat','fun','dog'],['mat','fun','dog','cat'],['fun','dog','cat','垫'],
['老鼠','狗','本','垫子'],['狗','垫子','猫','乐趣'], ...
]

my_list 有 200704 个元素

注意这里
my_list[0] = ['狗','猫','垫子','乐趣']
狗->猫->垫子->乐趣->狗
my_list[3] = ['cat','mat','fun','dog']
猫->垫子->乐趣->狗->猫
my_list[4] = ['mat','fun','dog','cat']
垫子->乐趣->狗->猫->垫子
my_list[5] = ['fun','dog','cat','mat']
有趣->狗->猫->垫子->有趣
循环往复,它们都是一样的。所以他们应该被标记为重复。

注意:
my_list[0] = ['狗','猫','垫子','乐趣']
my_list[7] = ['狗','垫子','猫','乐趣']
这些不应该被标记为重复,因为它们是循环的,它们是不同的。

同样,
my_list[2] = ['dog','ben','mat','rat']
my_list[6] = ['rat','dog','ben','mat']
它们应该被标记为重复。

def remove_circular_duplicates(my_list):
    # the quicker and more elegent logic here

    # the function should identify that my_list[0], my_list[3], my_list[4] and my_list[5] are circular duplicates
    # keep only my_list[0] and delete the rest 3
    # same for my_list[2] and my_list[6] and so on

    return (my_list_with_no_circular_duplicates)

----------------------------------- -----------------
我的尝试:
-------------------------------------------------- --------------
这可行,但需要 3 个多小时才能完成 200704 个元素。
而且它也不是一种优雅的方式..(请原谅我的水平)

t=my_list
tLen=len(t)
while i<tLen:
    c=c+1
    if c>2000:
        # this is just to keep you informed of the progress
        print(f'{i} of {tLen} finished ..')
        c=0
    if (finalT[i][4]=='unmarked'):
        # make 0-1-2-3 -> 1-2-3-0 and check any duplicates
        x0,x1,x2,x3 = t[i][1],t[i][2],t[i][3],t[i][0]
        # make 0-1-2-3 -> 2-3-0-1 and check any duplicates
        y0,y1,y2,y3 = t[i][2],t[i][3],t[i][0],t[i][1]
        # make 0-1-2-3 -> 3-0-1-2 and check any duplicates
        z0,z1,z2,z3 = t[i][3],t[i][0],t[i][1],t[i][2]
        while j<tLen:
            if (finalT[j][4]=='unmarked' and j!=i):
                #j!=i skips checking the same (self) element
                tString=t[j][0]+t[j][1]+t[j][2]+t[j][3]
                if (x0+x1+x2+x3 == tString) or (y0+y1+y2+y3 == tString) or (z0+z1+z2+z3 == tString):
                    # duplicate found, mark it as 'duplicate'
                    finalT[j][4]='duplicate'
                tString=''
            j=j+1
        finalT[i][4] = 'original'
        j=0
    i=i+1
# make list of only those marked as 'original'
i=0
ultimateT = []
while i<tLen:
    if finalT[i][4] == 'original':
        ultimateT.append(finalT[i])
    i=i+1
# strip the 'oritinal' mark and keep only the quad
i=0
ultimateTLen=len(ultimateT)
while i<ultimateTLen:
    ultimateT[i].remove('original')
    i=i+1
my_list_with_no_curcular_duplicates = ultimateT

print (f'\n\nDONE!!  \nStarted at: {start_time}\nEnded at {datetime.datetime.now()}')
return my_list_with_no_circular_duplicates

我想要的是一种更快的方式来做同样的事情。
提前 Tnx。

【问题讨论】:

    标签: python list duplicates logic circular-dependency


    【解决方案1】:

    您的实现是一个 n 平方算法,这意味着对于大型数据集,实现时间会急剧增加。 200,000 平方是一个非常大的数字。您需要将其转换为 n 阶或 n-log(n) 算法。为此,您需要对数据进行预处理,以便您可以检查循环等效项是否也在列表中,而无需搜索列表。为此,将每个条目放入一个表格中,无需遍历列表即可对其进行比较。我建议您轮换每个条目,以便它首先具有按字母顺序排列的第一项。例如将 ['dog','cat','mat','fun'] 更改为 ['cat','mat','fun','dog']。这是一次处理列表中每个元素的顺序 n 操作。

    然后将它们全部采用通用格式,您有多种选择来确定每个条目是否是唯一的。我会用一套。对于每个项目,检查该项目是否在一个集合中,如果不是,它是唯一的,应该添加到集合中。如果该项目已在集合中,则已找到等效项目并且可以删除该项目。检查一个项目是否在一个集合中是 Python 中的一个常数时间操作。它通过使用哈希表来索引以查找项目而不需要搜索来做到这一点。结果是这也是一个命令 n 操作,通过每个条目进行检查。总体而言,该算法是 n 阶的,并且会比您正在做的要快得多。

    【讨论】:

    • 有趣。花了一些时间来解决我的问题,但这个逻辑应该有效。关于将 ['dog','cat','mat','fun'] 排序为 ['cat','mat','fun','dog'] 而不干扰循环顺序的任何建议?顺便说一句,Tnx 快速回复。
    • 由于只有 4 个值,您可以使用蛮力方法。如果 t 是 4 个值的列表,则可以使用: m = min(t, t[1:4]+t[0:1], t[2:4]+t[0:2], t[ 3:4]+t[0:3])
    • 在大约 12 秒内处理它! Tnx。
    【解决方案2】:

    @BradBudlong
    Brad Budlong 的回答是正确的。 以下是相同的实现结果。

    我的方法(在问题中给出):
    所需时间:~274 分钟
    结果:len(my_list_without_circular_duplicates) >> 50176

    Brad Budlong 的方法:
    所用时间:~12 秒(太棒了!)
    结果:len(my_list_without_circular_duplicates) >> 50176

    以下只是 Brad Budlong 方法的实现:

    # extract all individual words like 'cat', 'rat', 'fun' and put in a list without duplicates 
    all_non_duplicate_words_from_my_list = {.. the appropriate code here}
    # and sort them alphabetically
    alphabetically_sorted_words = sorted(all_non_duplicate_words_from_my_list)
    
    # mark all as 'unsorted'
    all_q_marked=[]
    for i in my_list:
        all_q_marked.append([i,'unsorted'])
    
    # format my_list- in Brad's words,
    # rotate each entry so that it has the alphabetically first item first. 
    # For example change ['dog','cat','mat','fun'] to ['cat','mat','fun','dog'] 
    for w in alphabetically_sorted_words:
        print(f'{w} in progress ..')
        for q in all_q_marked:
            if q[1]=='unsorted':
                # check if the word exist in the quad
                if w in q[0]:
                    # word exist, then rotate this quad to put that word in first place
                    # rotation_count=q[0].index(w) -- alternate method lines
                    quad=q[0]
                    for j in range(4):
                        quad=quad[-1:] + quad[:-1]
                        if quad[0]==w:
                            q[0]=quad
                            break
                    # mark as sorted
                    q[1]='sorted'
    
    # strip the 'sorted' mark and keep only the quad
    i=0
    formatted_my_list=[]
    while i<len(all_q_marked):
        formatted_my_list.append(all_q_marked[i][0])
        i=i+1
    
    # finally remove duplicate lists in the list
    my_list_without_circular_duplicates = [list(t) for t in set(tuple(element) for element in formatted_my_list)]
    print (my_list_without_circular_duplicates)
    

    请注意,尽管它仍然迭代和处理整个 all_q_marked (200704) 的 alphabetically_sorted_words (201),但随着 all_q_marked 中的元素被标记为“已排序”,处理时间呈指数级减少。

    【讨论】:

      猜你喜欢
      • 2021-11-28
      • 1970-01-01
      • 1970-01-01
      • 2020-05-10
      • 2018-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多