তালিকার তালিকা থেকে সদৃশ সরিয়ে ফেলা হচ্ছে


116

পাইথনে আমার তালিকার একটি তালিকা রয়েছে:

k = [[1, 2], [4], [5, 6, 2], [1, 2], [3], [4]]

এবং আমি এটি থেকে সদৃশ উপাদানগুলি মুছে ফেলতে চাই। এটি যদি আমি ব্যবহার করতে পারি এমন তালিকার একটি সাধারণ তালিকা ছিল না set। তবে দুর্ভাগ্যজনক যে তালিকাটি হ্যাশযোগ্য নয় এবং তালিকার সেট তৈরি করতে পারে না। কেবল টুপলসের of সুতরাং আমি সমস্ত তালিকা টিপলগুলিতে পরিণত করতে পারি তারপরে সেট এবং আবার তালিকাগুলিতে ব্যবহার করতে পারি। তবে এটি দ্রুত নয়।

কীভাবে এটি সবচেয়ে কার্যকর উপায়ে করা যেতে পারে?

উপরের তালিকার ফলাফলটি হওয়া উচিত:

k = [[5, 6, 2], [1, 2], [3], [4]]

আমি অর্ডার সংরক্ষণ সম্পর্কে যত্ন করি না।

দ্রষ্টব্য: এই প্রশ্নটি একই রকম তবে আমার যা প্রয়োজন তা পুরোপুরি নয়। অনুসন্ধান করা হয়েছে তবে সঠিক সদৃশ খুঁজে পাওয়া যায় নি।


মাপকাঠিতে:

import itertools, time


class Timer(object):
    def __init__(self, name=None):
        self.name = name

    def __enter__(self):
        self.tstart = time.time()

    def __exit__(self, type, value, traceback):
        if self.name:
            print '[%s]' % self.name,
        print 'Elapsed: %s' % (time.time() - self.tstart)


k = [[1, 2], [4], [5, 6, 2], [1, 2], [3], [5, 2], [6], [8], [9]] * 5
N = 100000

print len(k)

with Timer('set'):
    for i in xrange(N):
        kt = [tuple(i) for i in k]
        skt = set(kt)
        kk = [list(i) for i in skt]


with Timer('sort'):
    for i in xrange(N):
        ks = sorted(k)
        dedup = [ks[i] for i in xrange(len(ks)) if i == 0 or ks[i] != ks[i-1]]


with Timer('groupby'):
    for i in xrange(N):
        k = sorted(k)
        dedup = list(k for k, _ in itertools.groupby(k))

with Timer('loop in'):
    for i in xrange(N):
        new_k = []
        for elem in k:
            if elem not in new_k:
                new_k.append(elem)

সংক্ষিপ্ত তালিকার জন্য দ্রুততম "লুপ ইন" (চতুষ্কোণ পদ্ধতি)। দীর্ঘ তালিকাগুলির জন্য এটি দ্রুততর তবে গ্রুপবাই পদ্ধতি বাদে সবাই everyone এটা কোনো কিছু হলো?

সংক্ষিপ্ত তালিকার জন্য (কোডটিতে একটি), 100000 পুনরাবৃত্তি:

[set] Elapsed: 1.3900001049
[sort] Elapsed: 0.891000032425
[groupby] Elapsed: 0.780999898911
[loop in] Elapsed: 0.578000068665

দীর্ঘ তালিকার জন্য (কোডটিতে একটিটি 5 বার নকল করা হয়েছে):

[set] Elapsed: 3.68700003624
[sort] Elapsed: 3.43799996376
[groupby] Elapsed: 1.03099989891
[loop in] Elapsed: 1.85900020599

1
"এটি দ্রুত নয়" এর দ্বারা আপনি কী বোঝাতে চেয়েছেন যে আপনি এটির সময়সীমা বেঁধে দিয়েছেন এবং এটি আপনার অ্যাপ্লিকেশনটির পক্ষে যথেষ্ট দ্রুত নয়, বা আপনি মনে করেন যে এটি দ্রুত নয়?
টর্স্টেন মেরেক

@ টর্স্টেন, স্মার্ট পদ্ধতি হিসাবে এটি খুব বেশি অনুলিপি করার মতো মনে হচ্ছে। দুঃখিত, অন্ত্র অনুভূতি।
টিপলগুলিতে

@ জহরপোপভ: পাইথন কীভাবে কাজ করে তা জানেন না , বিদ্যমান উপাদানগুলির জন্য কেবল নতুন পাত্রে কিছুই কপি করা হবে না (যদিও
ইনটসের ক্ষেত্রে

3
1. বাছাইয়ের পদ্ধতি ব্যবহারের পদ্ধতিগুলি ডিফল্ট হয়, কারণ "কে" বাছাই করা বৈকল্পিকের কাছে প্রত্যাবর্তন করে। ২. শেষ পদ্ধতিটি দ্রুততর কারণ আপনি পরীক্ষার ডেটা তৈরির উপায়টি আপনাকে সর্বোচ্চ ৪ টি স্বতন্ত্র উপাদান সহ ফেলে দেয় leaves চেষ্টা করুন। _ এর মধ্যে (100)] এর জন্য কে = [[ইনট্রে (ইউ) আপনার জন্য স্ট্রিম (এলোমেলো.আরেন্ডারেঞ্জ (1, 1000))]
টর্স্টেন মেরেক

@ টর্স্টেন: স্থির ধন্যবাদ 10 এর তালিকায় কেবলমাত্র একটি সদৃশ থাকা সত্ত্বেও লুপ পদ্ধতিটি দ্রুত
জহরপোপভ

উত্তর:


167
>>> k = [[1, 2], [4], [5, 6, 2], [1, 2], [3], [4]]
>>> import itertools
>>> k.sort()
>>> list(k for k,_ in itertools.groupby(k))
[[1, 2], [3], [4], [5, 6, 2]]

itertoolsএই ধরণের সমস্যার প্রায়শই দ্রুত এবং সর্বাধিক শক্তিশালী সমাধান সরবরাহ করে এবং এর সাথে ঘনিষ্ঠভাবে পরিচিত হওয়ার পক্ষে ভাল ! -)

সম্পাদনা : আমি যেমনটি একটি মন্তব্যে উল্লেখ করেছি, স্বাভাবিক অপ্টিমাইজেশান প্রচেষ্টা বড় ইনপুটগুলিতে (বিগ-ও পদ্ধতির) উপর নিবদ্ধ থাকে কারণ এটি এত সহজ যে এটি প্রচেষ্টায় ভাল আয় দেয়। তবে কখনও কখনও (মূলত "ট্র্যাজিক্যালি ক্রুশিয়াল বাধাগুলি" কোডের গভীর অভ্যন্তরীণ লুপগুলিতে যা কার্য সম্পাদনের সীমা সীমাবদ্ধ করে দেয়) কোনওটিকে আরও বিশদে যেতে হবে, সম্ভাব্যতা বন্টন সরবরাহ করতে হবে, কোন পারফরম্যান্সকে উপযুক্ত করতে হবে তা সিদ্ধান্ত নেওয়ার ক্ষেত্রে (সম্ভবত উপরের আবদ্ধ বা ৯০ তম সেন্টিমিট একটি গড় বা মিডিয়ানের চেয়ে বেশি গুরুত্বপূর্ণ, কারও অ্যাপসের উপর নির্ভর করে), ইনপুট ডেটার বৈশিষ্ট্যগুলির উপর নির্ভর করে বিভিন্ন অ্যালগরিদম বাছাই করতে শুরুতে সম্ভবত-হিউরিস্টিক চেকগুলি সম্পাদন করে।

"পয়েন্ট" পারফরম্যান্সের যত্নবান পরিমাপ (নির্দিষ্ট ইনপুটটির জন্য কোড এ বনাম কোড বি) এই অত্যন্ত ব্যয়বহুল প্রক্রিয়ার একটি অংশ এবং মানক লাইব্রেরি মডিউলটি timeitএখানে সহায়তা করে। তবে শেল প্রম্পটে এটি ব্যবহার করা সহজ। উদাহরণস্বরূপ, এই সমস্যার জন্য সাধারণ পদ্ধতির প্রদর্শন করতে এখানে একটি ছোট মডিউল দেওয়া হয়েছে, এটি সংরক্ষণ করুন nodup.py:

import itertools

k = [[1, 2], [4], [5, 6, 2], [1, 2], [3], [4]]

def doset(k, map=map, list=list, set=set, tuple=tuple):
  return map(list, set(map(tuple, k)))

def dosort(k, sorted=sorted, xrange=xrange, len=len):
  ks = sorted(k)
  return [ks[i] for i in xrange(len(ks)) if i == 0 or ks[i] != ks[i-1]]

def dogroupby(k, sorted=sorted, groupby=itertools.groupby, list=list):
  ks = sorted(k)
  return [i for i, _ in itertools.groupby(ks)]

def donewk(k):
  newk = []
  for i in k:
    if i not in newk:
      newk.append(i)
  return newk

# sanity check that all functions compute the same result and don't alter k
if __name__ == '__main__':
  savek = list(k)
  for f in doset, dosort, dogroupby, donewk:
    resk = f(k)
    assert k == savek
    print '%10s %s' % (f.__name__, sorted(resk))

python nodup.pyজিনিসকে সমান পদক্ষেপে রাখার জন্য স্যানিটি চেক (যখন আপনি কেবল করবেন তখন সম্পাদন করা ) এবং বেসিক উত্তোলন কৌশল (প্রতিটি গতির জন্য ধ্রুবক বিশ্বব্যাপী নাম স্থানীয় করুন ) নোট করুন ।

এখন আমরা ছোট উদাহরণের তালিকায় চেক পরিচালনা করতে পারি:

$ python -mtimeit -s'import nodup' 'nodup.doset(nodup.k)'
100000 loops, best of 3: 11.7 usec per loop
$ python -mtimeit -s'import nodup' 'nodup.dosort(nodup.k)'
100000 loops, best of 3: 9.68 usec per loop
$ python -mtimeit -s'import nodup' 'nodup.dogroupby(nodup.k)'
100000 loops, best of 3: 8.74 usec per loop
$ python -mtimeit -s'import nodup' 'nodup.donewk(nodup.k)'
100000 loops, best of 3: 4.44 usec per loop

নিশ্চিত করে যে চতুষ্কোণিক পদ্ধতির কয়েকটি অনুলিপি মান সহ ক্ষুদ্র তালিকার জন্য আকর্ষণীয় করে তুলতে যথেষ্ট-পর্যাপ্ত ধ্রুবক রয়েছে। নকল ছাড়াই একটি সংক্ষিপ্ত তালিকা সহ:

$ python -mtimeit -s'import nodup' 'nodup.donewk([[i] for i in range(12)])'
10000 loops, best of 3: 25.4 usec per loop
$ python -mtimeit -s'import nodup' 'nodup.dogroupby([[i] for i in range(12)])'
10000 loops, best of 3: 23.7 usec per loop
$ python -mtimeit -s'import nodup' 'nodup.doset([[i] for i in range(12)])'
10000 loops, best of 3: 31.3 usec per loop
$ python -mtimeit -s'import nodup' 'nodup.dosort([[i] for i in range(12)])'
10000 loops, best of 3: 25 usec per loop

চতুর্ভুজ পদ্ধতির খারাপ নয়, তবে বাছাই এবং গ্রুপবাইগুলি আরও ভাল। ইত্যাদি ইত্যাদি

যদি (পারফরম্যান্সের আবেশের হিসাবে প্রস্তাবিত হয়) এই অপারেশনটি আপনার ধাক্কা-সীমানা অ্যাপ্লিকেশনটির মূল অভ্যন্তরীণ লুপে রয়েছে, তবে অন্যান্য প্রতিনিধি ইনপুট নমুনাগুলিতে একই ধরণের পরীক্ষাগুলি চেষ্টা করার মতো এটি সম্ভবত কিছু সাধারণ পরিমাপ সনাক্তকরণের পক্ষে মূল্যবান যা আপনাকে বোধগম্যভাবে দিতে পারে এক বা অন্য পদ্ধতির চয়ন করুন (তবে পরিমাপটি অবশ্যই অবশ্যই দ্রুত)।

এটির জন্য আলাদা প্রতিনিধিত্ব রাখার বিষয়টি বিবেচনা করা ভাল k- কেন এটি প্রথমে টিপলস সেট না করে তালিকার একটি তালিকা হতে হবে? যদি সদৃশ অপসারণের কাজটি ঘন ঘন হয় এবং প্রোফাইলিং এটিকে প্রোগ্রামটির পারফরম্যান্সের বাধা হিসাবে দেখাতে পারে, সমস্ত সময় টিপলস সেট করে রাখে এবং কেবলমাত্র যেখানে প্রয়োজন হয় তা থেকে তালিকার একটি তালিকা পাওয়া যায়, উদাহরণস্বরূপ, সামগ্রিকভাবে দ্রুত হতে পারে।


@ আলেক্স বিকল্পের জন্য ধন্যবাদ। ড্যানবেনের মতো একই গতি সম্পর্কে এই পদ্ধতিটি, কয়েক শতাংশ দ্রুত
জহরপোপভ

@ অ্যালেক্স: আশ্চর্যজনকভাবে এটি সংক্ষিপ্ত তালিকার জন্য একটি
নিষ্পাপ চতুষ্কোণ

@ জাজারপোভভ: এটি কেবল আপনার বিশেষ ক্ষেত্রে সিএফ। প্রশ্নে আমার মন্তব্য।
টর্স্টেন মেরেক

@ জাজারপোপভ, আপনি যদি তালিকা এবং সাবলিস্টের দৈর্ঘ্য এবং নকলের সুযোগের সম্ভাবনা বন্টন দেন তবে কোনও প্রদত্ত কোডের জন্য রানটাইম সম্ভাব্যতা বন্টন গণনা / পরিমাপ করা এবং আপনার প্রয়োজনীয় যা পরিমাপ প্রয়োজন তা অপ্টিমাইজ করা সম্ভব (মধ্যমা, গড়, 90 তম) সেন্টিলে, যাই হোক না কেন) এটি খুব কম আরওআইয়ের কারণে খুব কমই সম্পন্ন হয়েছে: সাধারণত কেউ বড় ইনপুটগুলির ক্ষেত্রে (বিগ-ও পদ্ধতির) খুব সহজেই মনোনিবেশ করে যেখানে নিকৃষ্টতর অ্যালগরিদমগুলি কার্যত ক্ষতিকারকভাবে পারফরম্যান্সকে আঘাত করে। এবং আমি আপনাকে আপনার Q- তে কোনও সম্ভাবনা বিতরণ নির্দিষ্ট করে দেখছি না ;-)।
অ্যালেক্স মার্টেলি

@ জহরপভ, খুশি হয়েছ!
অ্যালেক্স মার্টেলি

21

এটি ম্যানুয়ালি করা, একটি নতুন kতালিকা তৈরি করা এবং এন্ট্রি যোগ করা এখনও পাওয়া যায় নি:

k = [[1, 2], [4], [5, 6, 2], [1, 2], [3], [4]]
new_k = []
for elem in k:
    if elem not in new_k:
        new_k.append(elem)
k = new_k
print k
# prints [[1, 2], [4], [5, 6, 2], [3]]

উপলব্ধি করা সহজ, এবং আপনি প্রতিটি উপাদানের প্রথম সংক্রমণের ক্রমটি সংরক্ষণ করেন যে এটি কার্যকর হওয়া উচিত তবে আমি অনুমান করি যে এটি জটিলতার মধ্যে দ্বিঘাতের কারণ আপনি new_kপ্রতিটি উপাদানটির পুরো অনুসন্ধান করছেন ।


@ পল: খুব অদ্ভুত - এই পদ্ধতিটি অন্য সকলের চেয়ে দ্রুত
zhaharpopov

আমি সন্দেহ করি খুব দীর্ঘ তালিকার জন্য এই পদ্ধতিটি দ্রুততর হবে না। এটি আপনার আবেদনের উপর নির্ভর করবে: যদি আপনার কাছে কেবল দুটি ডুপ্লিকেট সহ ছয়-উপাদান তালিকা থাকে তবে যে কোনও সমাধান যথেষ্ট দ্রুত হতে পারে এবং আপনার স্পষ্ট কোডের সাথে চলতে হবে।
পল স্টিফেনসন

@ জহরপোপভ, এটি আপনার মানদণ্ডে চতুর্ভুজ নয় কারণ আপনি একই তালিকাটিকে বারবার নকল করে তোলেন। আপনি একটি লিনিয়ার কর্নারের কেস নিয়ে বেঞ্চমার্ক করছেন।
মাইক গ্রাহাম

k = ([[1, 2], [4], [5, 6, 2], [1, 2], [3], [5, 2], [6], [8], [9]] +[[x] for x in range(1000)]) *5চতুর্ভুজীয় আচরণটি দুর্দান্তভাবে প্রদর্শন করবে
জন লা রুই

17
>>> k = [[1, 2], [4], [5, 6, 2], [1, 2], [3], [4]]
>>> k = sorted(k)
>>> k
[[1, 2], [1, 2], [3], [4], [4], [5, 6, 2]]
>>> dedup = [k[i] for i in range(len(k)) if i == 0 or k[i] != k[i-1]]
>>> dedup
[[1, 2], [3], [4], [5, 6, 2]]

এটি প্রয়োজনীয়ভাবে দ্রুত কিনা তা আমি জানি না, তবে আপনাকে টিপলস এবং সেট ব্যবহার করতে হবে না।


ধন্যবাদ দানবেন। এই দ্রুত tuples ঘুরিয়ে তারপর 'সেট' তারপর তালিকায় ফিরে?
zhaharpopov

উভয় deduping পদ্ধতি লিখুন, ব্যবহার কিছু র্যান্ডম তালিকা জেনারেট - তুমি সহজে পরীক্ষা করে পারা random, এবং সময় এটি time
Danben

4

setএই সমস্যার সমস্ত সম্পর্কিত সম্পর্কিত সমাধানগুলির setপুনরাবৃত্তির আগে একটি সম্পূর্ণ তৈরি করা প্রয়োজন ।

তালিকার তালিকাটি পুনরাবৃত্তি করে এবং "দেখা "তে যুক্ত করে এই অলস এবং একই সাথে অর্ডার সংরক্ষণ করা সম্ভব set। তারপরে এই তালিকাটিতে যদি এটি পাওয়া না যায় তবে কেবলমাত্র একটি তালিকা উত্পন্ন করুন set

এই unique_everseenরেসিপিটি itertools ডক্সে উপলব্ধ । এটি তৃতীয় পক্ষের toolzগ্রন্থাগারেও পাওয়া যায়:

from toolz import unique

k = [[1, 2], [4], [5, 6, 2], [1, 2], [3], [4]]

# lazy iterator
res = map(list, unique(map(tuple, k)))

print(list(res))

[[1, 2], [4], [5, 6, 2], [3]]

নোট করুন যে tupleরূপান্তরগুলি প্রয়োজনীয় কারণ তালিকাগুলি হ্যাশযোগ্য নয়।


3

এমনকি আপনার "দীর্ঘ" তালিকাটি খুব ছোট। এছাড়াও, আপনি কি তাদের প্রকৃত ডেটা মেলানোর জন্য চয়ন করেছেন? এই ডেটাগুলি দেখতে আসলে যা দেখায় তার সাথে পারফরম্যান্স পরিবর্তিত হয়। উদাহরণস্বরূপ, দীর্ঘ তালিকা তৈরি করার জন্য আপনার কাছে একটি সংক্ষিপ্ত তালিকা বার বার করা হয়েছে। এর অর্থ হল যে চতুর্ভুজ সমাধানটি আপনার মানদণ্ডগুলিতে রৈখিক, তবে বাস্তবে নয়।

প্রকৃতপক্ষে-বৃহত তালিকার জন্য, সেট কোডটি আপনার সেরা বাজি - এটি লিনিয়ার (যদিও স্থান ক্ষুধার্ত)। বাছাইকরণ এবং গোষ্ঠীভুক্ত পদ্ধতিগুলি হ'ল (এন লগ এন) এবং পদ্ধতিটির লুপটি স্পষ্টতই চতুর্ভুজযুক্ত, সুতরাং আপনি জানেন কী এইগুলি কীভাবে স্কেল হবে এন সত্যিই বড় হবে। আপনি যদি বিশ্লেষণ করছেন এমন ডেটার যদি এটিই আসল আকার হয় তবে কে যত্ন করে? এটা ক্ষুদ্র।

ঘটনাক্রমে, আমি সেটটি তৈরি করার জন্য যদি একটি মধ্যবর্তী তালিকা তৈরি না করি তবে আমি একটি পরিবর্তনযোগ্য স্পিডআপ দেখছি, এটি যদি আমি প্রতিস্থাপন করি তবে

kt = [tuple(i) for i in k]
skt = set(kt)

সঙ্গে

skt = set(tuple(i) for i in k)

আসল সমাধান আরও তথ্যের উপর নির্ভর করতে পারে: আপনি কি নিশ্চিত যে তালিকার একটি তালিকা সত্যই আপনার প্রয়োজনীয় প্রতিনিধিত্ব?


3

টিপলের তালিকা এবং remove of সদৃশগুলি অপসারণ করতে ব্যবহার করা যেতে পারে

>>> [list(tupl) for tupl in {tuple(item) for item in k }]
[[1, 2], [5, 6, 2], [3], [4]]
>>> 

1

কী হিসাবে টিপল সহ একটি অভিধান তৈরি করুন এবং কীগুলি মুদ্রণ করুন।

  • কী হিসাবে টিপল এবং মান হিসাবে সূচী দিয়ে অভিধান তৈরি করুন
  • অভিধানের কীগুলির মুদ্রণ তালিকা

k = [[1, 2], [4], [5, 6, 2], [1, 2], [3], [4]]

dict_tuple = {tuple(item): index for index, item in enumerate(k)}

print [list(itm) for itm in dict_tuple.keys()]

# prints [[1, 2], [5, 6, 2], [3], [4]]

1

এই কাজ করা উচিত.

k = [[1, 2], [4], [5, 6, 2], [1, 2], [3], [4]]

k_cleaned = []
for ele in k:
    if set(ele) not in [set(x) for x in k_cleaned]:
        k_cleaned.append(ele)
print(k_cleaned)

# output: [[1, 2], [4], [5, 6, 2], [3]]

0

আশ্চর্যের বিষয় হল, উপরের উত্তরগুলি 'সদৃশ' মুছে ফেলে তবে আমি যদি নকল মানটিও মুছতে চাই তবে কি হবে ?? নিম্নলিখিতগুলি কার্যকর হওয়া উচিত এবং মেমরিতে কোনও নতুন অবজেক্ট তৈরি করে না!

def dictRemoveDuplicates(self):
    a=[[1,'somevalue1'],[1,'somevalue2'],[2,'somevalue1'],[3,'somevalue4'],[5,'somevalue5'],[5,'somevalue1'],[5,'somevalue1'],[5,'somevalue8'],[6,'somevalue9'],[6,'somevalue0'],[6,'somevalue1'],[7,'somevalue7']]


print(a)
temp = 0
position = -1
for pageNo, item in a:
    position+=1
    if pageNo != temp:
        temp = pageNo
        continue
    else:
        a[position] = 0
        a[position - 1] = 0
a = [x for x in a if x != 0]         
print(a)

এবং o / p হ'ল:

[[1, 'somevalue1'], [1, 'somevalue2'], [2, 'somevalue1'], [3, 'somevalue4'], [5, 'somevalue5'], [5, 'somevalue1'], [5, 'somevalue1'], [5, 'somevalue8'], [6, 'somevalue9'], [6, 'somevalue0'], [6, 'somevalue1'], [7, 'somevalue7']]
[[2, 'somevalue1'], [3, 'somevalue4'], [7, 'somevalue7']]

-1

আরেকটি সম্ভবত আরও জেনেরিক এবং সহজ সমাধান হ'ল একটি অভিধান তৈরি করা যা বস্তুর স্ট্রিং সংস্করণ দ্বারা কীড করা হয় এবং শেষে মানগুলি পাওয়া যায়:

>>> dict([(unicode(a),a) for a in [["A", "A"], ["A", "A"], ["A", "B"]]]).values()
[['A', 'B'], ['A', 'A']]

ক্যাচটি হ'ল এটি কেবল সেই সামগ্রীর জন্য কাজ করে যার স্ট্রিং প্রতিনিধিত্ব একটি যথেষ্ট পরিমাণে অনন্য কী (যা বেশিরভাগ নেটিভ অবজেক্টের ক্ষেত্রে সত্য)।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.