সংরক্ষণের অর্ডার সহ আপনি কীভাবে একটি তালিকা থেকে সদৃশ সরিয়ে ফেলবেন?


768

অর্ডার সংরক্ষণের সময় পাইথনের তালিকা থেকে সদৃশ সরিয়ে এমন কোনও বিল্ট-ইন রয়েছে? আমি জানি যে সদৃশ অপসারণের জন্য আমি একটি সেট ব্যবহার করতে পারি, তবে এটি মূল ক্রমটি নষ্ট করে। আমি আরও জানি যে আমি নিজের মতো করে নিজের মতো করে নিতে পারি:

def uniq(input):
  output = []
  for x in input:
    if x not in output:
      output.append(x)
  return output

( এই কোড নমুনার জন্য উন্মুক্ত করার জন্য ধন্যবাদ ।)

তবে আমি যদি সম্ভব হয় তবে বিল্ট-ইন বা আরও বেশি পাইথোনিক আইডিয়মটি উপভোগ করতে চাই।

সম্পর্কিত প্রশ্ন: পাইথনে, কোনও তালিকা থেকে সদৃশ অপসারণের জন্য দ্রুততম অ্যালগরিদম কী কী যাতে ক্রম সংরক্ষণের সময় সমস্ত উপাদান অনন্য থাকে ?

উত্তর:


762

এখানে আপনার কয়েকটি বিকল্প রয়েছে: http://www.peterbe.com/plog/uniqifiers-benchmark

দ্রুততম এক:

def f7(seq):
    seen = set()
    seen_add = seen.add
    return [x for x in seq if not (x in seen or seen_add(x))]

শুধু কল seen.addকরার seen_addপরিবর্তে কেন বরাদ্দ করা হবে seen.add? পাইথন একটি গতিশীল ভাষা, এবং seen.addপ্রতিটি পুনরাবৃত্তির সমাধান স্থানীয় ভেরিয়েবলের সমাধানের চেয়ে ব্যয়বহুল। seen.addপুনরাবৃত্তির মধ্যে পরিবর্তিত হতে পারে, এবং রানটাইম এটি চালিয়ে যাওয়ার পক্ষে যথেষ্ট স্মার্ট নয়। এটি নিরাপদে খেলতে, এটিতে প্রতিবার অবজেক্টটি পরীক্ষা করতে হবে।

আপনি যদি একই ডেটাসেটে এই ফাংশনটি ব্যবহার করার পরিকল্পনা করে থাকেন তবে সম্ভবত আপনি অর্ডার করা সেটটি দিয়ে আরও ভাল হতে পারেন: http://code.activestate.com/recips/528878/

(1) সক্রিয়করণ প্রতি সন্নিবেশ, মোছা এবং সদস্য-চেক।

(ছোট অতিরিক্ত নোট: seen.add()সর্বদা ফিরে আসে None, সুতরাং উপরেরটি orকেবলমাত্র একটি সেট আপডেটের চেষ্টা করার উপায় হিসাবে রয়েছে, লজিকাল পরীক্ষার অবিচ্ছেদ্য অংশ হিসাবে নয়))


20
@ জেসিহিলন seen.addপুনরাবৃত্তির মধ্যে পরিবর্তন করতে পারে, এবং রানটাইমটি এতটা স্মার্ট নয় যে এটি রুল করতে পারে। নিরাপদে খেলতে, এটিতে প্রতিবার অবজেক্টটি পরীক্ষা করতে হবে। - আপনি যদি বাইটোকোডটি দিয়ে dis.dis(f)দেখেন তবে দেখতে পাবেন যে এটি প্রতিটি পুনরাবৃত্তিতে সদস্যটির LOAD_ATTRজন্য কার্যকর করে addideone.com/tz1Tll
মারকাস জারদারট

5
আমি যখন তালিকাগুলির তালিকায় এটির চেষ্টা করি তখন: টাইপরর: অনিবার্য প্রকার: 'তালিকা'
জেনস টিমারম্যান

7
আপনার সমাধানটি দ্রুততম নয়। পাইথন 3 এ (2 টি পরীক্ষা করা হয়নি) এটি দ্রুত (300k এন্ট্রি তালিকা - 0.045s (আপনার) বনাম 0.035s (এটির একটি): দেখেছি = সেট (); ফিরে আসুন [এক্সে লাইনে x এর জন্য এক্স না দেখানো হয়েছে এবং না দেখে.এডিডি (এক্স)]। আপনি করেছেন_আড্ড লাইনের কোনও গতি প্রতিক্রিয়া আমি খুঁজে পাইনি
ব্যবহারকারী 136036

3
@ user136036 দয়া করে আপনার পরীক্ষায় লিঙ্ক করুন। আপনি কতবার তাদের চালানো? seen_addউন্নতি হয় তবে সময় সিস্টেম সিস্টেম দ্বারা সংক্রামিত হতে পারে। পুরো সময়গুলি দেখতে আগ্রহী হবে
জামিলাক

2
পাইথন কোডটি যে কেউ লিখছেন, আপনার কাছে পঠনযোগ্যতা এবং সাধারণভাবে সম্মত পাইথন কনভেনশনগুলির বলিদানের আগে দু'বার ভাবতে হবে কেবল লুপ প্রতি আরও কয়েকটি ন্যানোসেকেন্ডগুলি খুঁজে বার করার জন্য। পরীক্ষা ছাড়াই এবং seen_add = seen.addফলন ছাড়াই গতি মাত্র 1% বৃদ্ধি পেয়েছে। এটা খুব তাৎপর্যপূর্ণ।
sleblanc

343

2016 সম্পাদনা করুন

রেমন্ড উল্লেখ করেছেন যে , পাইথন ৩.৫+ তে সিটিতে OrderedDictপ্রয়োগ করা হয়েছে, তালিকা বোধগম্যতাটি ধীরে ধীরে ধীরে ধীরে হবে OrderedDict(যদি না আপনি আসলে শেষে তালিকাটির প্রয়োজন হয় - এবং তারপরেও কেবল ইনপুট খুব সংক্ষিপ্ত হয় তবে)। সুতরাং 3.5+ এর জন্য সেরা সমাধানটি OrderedDict

গুরুত্বপূর্ণ সম্পাদনা 2015

হিসাবে @abarnert নোট, more_itertoolsলাইব্রেরী ( pip install more_itertools) একটি রয়েছে unique_everseenফাংশন যা কোনো ছাড়া এই সমস্যা সমাধানের জন্য নির্মিত অপাঠ্য ( not seen.add) পরিব্যক্তি তালিকা comprehensions হবে। এটিও দ্রুততম সমাধান:

>>> from  more_itertools import unique_everseen
>>> items = [1, 2, 0, 1, 3, 2]
>>> list(unique_everseen(items))
[1, 2, 0, 3]

কেবল একটি সাধারণ লাইব্রেরি আমদানি করুন এবং কোনও হ্যাক নেই। এটি এররটুলস রেসিপিটির বাস্তবায়ন থেকে আসে unique_everseenযা দেখতে মনে হয়:

def unique_everseen(iterable, key=None):
    "List unique elements, preserving order. Remember all elements ever seen."
    # unique_everseen('AAAABBBCCDAABBB') --> A B C D
    # unique_everseen('ABBCcAD', str.lower) --> A B C D
    seen = set()
    seen_add = seen.add
    if key is None:
        for element in filterfalse(seen.__contains__, iterable):
            seen_add(element)
            yield element
    else:
        for element in iterable:
            k = key(element)
            if k not in seen:
                seen_add(k)
                yield element

পাইথন সালে গৃহীত সাধারণ বাগ্ধারা (যা কাজ করে কিন্তু গতি, আমি এখন ব্যবহার করেন জন্য অপ্টিমাইজ করা নেই ) এই ব্যবহারের জন্য :2.7+unique_everseencollections.OrderedDict

রানটাইম: ও (এন)

>>> from collections import OrderedDict
>>> items = [1, 2, 0, 1, 3, 2]
>>> list(OrderedDict.fromkeys(items))
[1, 2, 0, 3]

এটি দেখতে অনেক সুন্দর দেখায়:

seen = set()
[x for x in seq if x not in seen and not seen.add(x)]

এবং কুৎসিত হ্যাক ব্যবহার করে না :

not seen.add(x)

যা এই set.addজায়গার উপর নির্ভর করে যে একটি অন্তর্ভুক্ত পদ্ধতি যা সর্বদা Noneতাই not Noneমূল্যায়ন করে True

তবে লক্ষ্য করুন যে হ্যাক সমাধানটি কাঁচা গতিতে দ্রুততর যদিও এটিতে একই রানটাইম জটিলতা ও (এন) রয়েছে।


5
কিছু কাস্টম ধরণের ডিকে রূপান্তরিত হচ্ছেন কেবল কীগুলি নেওয়ার জন্য? ঠিক আর একটি ক্রাচ।
নাকিলন

3
@ নকিলন আমি সত্যিই দেখতে পাচ্ছি না কিভাবে এটি ক্রাচ। এটি কোনও পরিবর্তনীয় অবস্থা প্রকাশ করে না, সুতরাং এটি সেই অর্থে এটি খুব পরিষ্কার। অভ্যন্তরীণভাবে পাইথন সেটগুলি ডিক () ( স্ট্যাকওভারফ্লো / প্রশ্নগুলি / 3949310/… ) দিয়ে প্রয়োগ করা হয় , সুতরাং মূলত আপনি কেবল অনুবাদক যেভাবেই করতেন তা করছেন।
ইমরান

কেবলমাত্র পার্শ্ব প্রতিক্রিয়াগুলি ব্যবহার করুন এবং করুন [seen.add(x) for x in seq if x not in seen], বা আপনি যদি বোঝার পার্শ্ব প্রতিক্রিয়াগুলি পছন্দ করেন না তবে কেবল একটি forলুপ ব্যবহার করুন : for x in seq: seen.add(x) if x not in seen else None(এখনও একটি ওয়ান-লাইনার, যদিও এই ক্ষেত্রে আমি মনে করি যে ওয়ান-লাইনার-নেসটি একটি চেষ্টা করার জন্য একটি নির্বোধ সম্পত্তি সমাধান।
এলে

@EMS যা আদেশ সংরক্ষণ করে না। আপনি ঠিক পাশাপাশি করতে পারে seen = set(seq)
flornquake

1
@ কম্মসফট আমি সম্মত, যদিও বাস্তবভাবে এটি প্রায় সর্বদা O (n) অতি সম্ভবত অত্যন্ত অসম্ভব খারাপ মামলার কারণে
জামিলাক

110

পাইথন ২.7-তে , মূল ক্রমে রাখার সময় পুনরাবৃত্তিযোগ্য থেকে সদৃশগুলি সরিয়ে ফেলার নতুন উপায়টি হ'ল:

>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

পাইথন 3.5 তে , অর্ডারডিক্টের একটি সি বাস্তবায়ন রয়েছে। আমার সময়গুলি দেখায় যে এটি এখন পাইথন 3.5 এর বিভিন্ন পদ্ধতির মধ্যে দ্রুত এবং সংক্ষিপ্ত উভয়ই।

পাইথন ৩.6-এ , নিয়মিত ডিক দুটি অর্ডারযুক্ত এবং কমপ্যাক্ট হয়ে ওঠে। (এই বৈশিষ্ট্যটি সিপিথন এবং পাইপাইয়ের জন্য রয়েছে তবে অন্যান্য বাস্তবায়নে এটি উপস্থিত নাও হতে পারে)। এটি আমাদের অর্ডার বজায় রাখার সময় ছাড়ের নতুন দ্রুততম উপায় দেয়:

>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

পাইথন ৩.7-এ , সমস্ত বাস্তবায়ন জুড়ে নিয়মিত আদেশ উভয়েরই গ্যারান্টিযুক্ত। সুতরাং, সবচেয়ে সংক্ষিপ্ত এবং দ্রুত সমাধানটি হ'ল:

>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

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


যতক্ষণ আমি OrderedDictশেষ পর্যন্ত কোনও তালিকায় রূপান্তর না করি ততক্ষণ এটি আমার মেশিনে থাকা অন্য যেকোন পদ্ধতির চেয়ে দ্রুত (অজগর 3.5) is যদি আমাকে এটিকে কোনও তালিকায় রূপান্তর করতে হয় তবে ছোট ইনপুটগুলির জন্য তালিকা বোধগম্যতাটি এখনও 1.5 গুণ বেশি দ্রুত হয়। বলেছিল, এই সমাধানটি অনেক পরিষ্কার।
সর্বোচ্চ 20

7
একমাত্র গ্যাচা হ'ল পুনরাবৃত্ত "উপাদানগুলি" অবশ্যই হ্যাশেবল হতে পারে - স্বেচ্ছাসেবী উপাদানগুলির সাথে পুনরাবৃত্ত হওয়ার সমতুল্য (তালিকার একটি তালিকা হিসাবে) ভাল
লাগবে

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

41
sequence = ['1', '2', '3', '3', '6', '4', '5', '6']
unique = []
[unique.append(item) for item in sequence if item not in unique]

অনন্য → ['1', '2', '3', '6', '4', '5']


28
এটি লক্ষণীয় যে এটি চলেn^2
goncalopp

25
Ick। ২ টি ধর্মঘট: সদস্যপদ পরীক্ষার জন্য একটি তালিকা ব্যবহার করে (ধীর, ও (এন)) এবং পার্শ্ব প্রতিক্রিয়াগুলির জন্য একটি তালিকা বোঝার ব্যবহার ( Noneপ্রক্রিয়াটিতে আরও একটি রেফারেন্স তৈরি করা!)
মার্টিজান পিটারস

1
আমি @ মার্তিজজনপিটারের সাথে একমত , পার্শ্ব প্রতিক্রিয়াগুলির সাথে তালিকাটি বোঝার জন্য কোনও কারণ নেইforপরিবর্তে কেবল একটি লুপ ব্যবহার করুন
জামিলাক

31

একটি মৃত ঘোড়াটিকে লাথি মারার জন্য নয় (এই প্রশ্নটি খুব পুরানো এবং ইতিমধ্যে প্রচুর ভাল উত্তর রয়েছে), তবে এখানে পান্ডাস ব্যবহার করে এমন একটি সমাধান দেওয়া হয়েছে যা অনেক পরিস্থিতিতে বেশ দ্রুত এবং এটি ব্যবহারের জন্য সহজ মৃত।

import pandas as pd

my_list = [0, 1, 2, 3, 4, 1, 2, 3, 5]

>>> pd.Series(my_list).drop_duplicates().tolist()
# Output:
# [0, 1, 2, 3, 4, 5]

27
from itertools import groupby
[ key for key,_ in groupby(sortedList)]

তালিকাটি এমনকি বাছাই করতে হবে না , পর্যাপ্ত শর্তটি হচ্ছে সমান মানগুলি একসাথে ভাগ করা হয়।

সম্পাদনা: আমি ধরে নিয়েছি যে "সংরক্ষণের অর্ডার" বোঝায় যে তালিকাটি আসলে অর্ডার করা হয়েছে। যদি এটি না হয় তবে মিজার্ডএক্স থেকে সমাধানটি সঠিক।

সম্প্রদায় সম্পাদনা: তবে এটি "একক উপাদানে ডুপ্লিকেট ধারাবাহিক উপাদান সংকোচনের" জন্য সবচেয়ে মার্জিত উপায়।


1
কিন্তু এটি অর্ডার সংরক্ষণ করে না!

1
এইচআরএম, এটি সমস্যাযুক্ত, যেহেতু আমি গ্যারান্টি দিতে পারি না যে তালিকার উপরে একবারে লুপিং না করে সমান মানগুলি একত্রে শ্রেণিবদ্ধ করা হয়েছে, যার মাধ্যমে আমি নকলগুলি ছাঁটাই করতে পারি।
জোশ গ্লোভার

আমি ধরে নিয়েছি যে "সংরক্ষণের আদেশ" সূচিত করেছে যে তালিকাটি আসলে অর্ডার করা হয়েছে।
রাফা ডগির্ড

1
ইনপুট তালিকার স্পেসিফিকেশনটি কিছুটা অস্পষ্ট। এমনকি মানগুলি একত্রে গোষ্ঠীভুক্ত করার দরকার নেই: [2, 1, 3, 1]। সুতরাং কোন মান রাখতে হবে এবং কোনটি মুছতে হবে?

1
@igorkf জোড়া (গুলি) এর দ্বিতীয় উপাদানটিকে উপেক্ষা করছেন।
রাফা ডাউগার্ড

24

আমি মনে করি আপনি যদি অর্ডার বজায় রাখতে চান,

আপনি এটি চেষ্টা করতে পারেন:

list1 = ['b','c','d','b','c','a','a']    
list2 = list(set(list1))    
list2.sort(key=list1.index)    
print list2

বা একইভাবে আপনি এটি করতে পারেন:

list1 = ['b','c','d','b','c','a','a']  
list2 = sorted(set(list1),key=list1.index)  
print list2 

আপনি এটি করতে পারেন:

list1 = ['b','c','d','b','c','a','a']    
list2 = []    
for i in list1:    
    if not i in list2:  
        list2.append(i)`    
print list2

এটি এই হিসাবে লেখা যেতে পারে:

list1 = ['b','c','d','b','c','a','a']    
list2 = []    
[list2.append(i) for i in list1 if not i in list2]    
print list2 

3
আপনার প্রথম দুটি উত্তর অনুমান করে যে তালিকার ক্রমটি বাছাইয়ের ক্রিয়াটি ব্যবহার করে পুনর্নির্মাণ করা যেতে পারে, তবে এটি এটি নাও হতে পারে।
রিচার্ড

5
বেশিরভাগ উত্তরগুলি পারফরম্যান্সের উপর নিবদ্ধ থাকে। কর্মক্ষমতা সম্পর্কে চিন্তার জন্য যথেষ্ট বড় নয় এমন তালিকার জন্য, সাজানো (সেট (তালিকা 1), কী = list1.index) আমার দেখা সেরা জিনিস। কোনও অতিরিক্ত আমদানি, কোনও অতিরিক্ত ফাংশন, কোনও অতিরিক্ত পরিবর্তনশীল নয় এবং এটি মোটামুটি সহজ এবং পাঠযোগ্য।
ডেরেক ভাইট

23

ইন পাইথন 3.7 এবং উপরোক্ত, অভিধান করছে নিশ্চিত তাদের কী সন্নিবেশ অর্ডার মনে রাখা। উত্তর এই প্রশ্ন সাম্প্রতিক অবস্থা সংক্ষিপ্ত বিবরণ।

OrderedDictসমাধান এইভাবে অপ্রচলিত হয়ে যায় এবং কোনো আমদানি বিবৃতি ছাড়া কেবলমাত্র আমরা ইস্যু করতে পারে:

>>> lst = [1, 2, 1, 3, 3, 2, 4]
>>> list(dict.fromkeys(lst))
[1, 2, 3, 4]

11

আরেকটি খুব পুরানো প্রশ্নের আরও দেরিতে উত্তরের জন্য:

itertoolsরেসিপি একটি ফাংশন যে এই আছে ব্যবহার আছে seenসেট কৌশল, কিন্তু:

  • একটি স্ট্যান্ডার্ড keyফাংশন পরিচালনা করে।
  • কোনও অদৃশ্য হ্যাক ব্যবহার করে না।
  • লুপটিকে seen.addএন-বার বার দেখার পরিবর্তে প্রাক-বাঁধাইয়ের মাধ্যমে লুপটি অনুকূলিত করে । ( f7এটিও করে তবে কিছু সংস্করণ তা করে না))
  • লুপটি ব্যবহার করে অনুকূলিত করে ifilterfalse, তাই আপনাকে পাইথনের অনন্য উপাদানগুলির পরিবর্তে কেবলমাত্র লুপ করতে হবে। (আপনি এখনও ifilterfalseঅবশ্যই তাদের সকলের ভিতরে পুনরাবৃত্তি করুন অবশ্যই, তবে এটি সিতে এবং আরও দ্রুত))

আসলে কি এর চেয়ে দ্রুত f7? এটি আপনার ডেটার উপর নির্ভর করে তাই আপনাকে এটি পরীক্ষা করে দেখতে হবে। আপনি যদি শেষে একটি তালিকা চান, একটি তালিকা f7কম্পম্প ব্যবহার করে এবং এখানে এটি করার কোনও উপায় নেই way (আপনি সরাসরি ইনগিংয়ের appendপরিবর্তে yieldকরতে পারেন, বা আপনি জেনারেটরটিকে listফাংশনটিতে খাওয়ানোতে পারেন , তবে একটিও কোনও লিস্টকম্পের অভ্যন্তরে LIST_APPEND এর মতো দ্রুত হতে পারে না)) যে কোনও হারে, সাধারণত কয়েকটি মাইক্রোসেকেন্ড আটকানো যেমন হয় না তেমন হয় না) সহজেই বোধগম্য, পুনরায় ব্যবহারযোগ্য, ইতিমধ্যে লিখিত ফাংশন হিসাবে গুরুত্বপূর্ণ যা আপনি সাজাতে চান যখন ডিএসইউ প্রয়োজন হয় না।

সমস্ত রেসিপি হিসাবে, এটি পাওয়া যায় more-iterools

আপনি যদি কেবল নোটিস চান তবে keyআপনি এটিকে আরও সহজ করতে পারেন:

def unique(iterable):
    seen = set()
    seen_add = seen.add
    for element in itertools.ifilterfalse(seen.__contains__, iterable):
        seen_add(element)
        yield element

আমি সম্পূর্ণরূপে উপেক্ষা করেছি more-itertoolsএটি পরিষ্কারভাবে সেরা উত্তর। একটি সহজ from more_itertools import unique_everseen list(unique_everseen(items))আমার চেয়ে অনেক দ্রুত পদ্ধতির এবং গ্রহণযোগ্য উত্তরের চেয়ে অনেক ভাল, আমি মনে করি লাইব্রেরি ডাউনলোডটি এর পক্ষে মূল্যবান। আমি সম্প্রদায়ে যাচ্ছি আমার উত্তর উইকি এবং এই মধ্যে যোগ করুন।
jamylak

11

শুধু একটি বহিস্থিত মডিউল থেকে অন্য (খুব performant) যেমন একটি কার্যকারিতা বাস্তবায়ন যোগ করার জন্য 1 : iteration_utilities.unique_everseen:

>>> from iteration_utilities import unique_everseen
>>> lst = [1,1,1,2,3,2,2,2,1,3,4]

>>> list(unique_everseen(lst))
[1, 2, 3, 4]

সময়

আমি কিছু সময় (পাইথন 3.6) এবং এই শো এটি দ্রুত অন্য সব বিকল্প আমি পরীক্ষিত সহ চেয়ে এর করেনি OrderedDict.fromkeys, f7এবং more_itertools.unique_everseen:

%matplotlib notebook

from iteration_utilities import unique_everseen
from collections import OrderedDict
from more_itertools import unique_everseen as mi_unique_everseen

def f7(seq):
    seen = set()
    seen_add = seen.add
    return [x for x in seq if not (x in seen or seen_add(x))]

def iteration_utilities_unique_everseen(seq):
    return list(unique_everseen(seq))

def more_itertools_unique_everseen(seq):
    return list(mi_unique_everseen(seq))

def odict(seq):
    return list(OrderedDict.fromkeys(seq))

from simple_benchmark import benchmark

b = benchmark([f7, iteration_utilities_unique_everseen, more_itertools_unique_everseen, odict],
              {2**i: list(range(2**i)) for i in range(1, 20)},
              'list size (no duplicates)')
b.plot()

এখানে চিত্র বর্ণনা লিখুন

এবং এটি নিশ্চিত করার জন্য যে আমি আরও নকলের সাথে একটি পরীক্ষা করেছি কেবল এটির কোনও ত্রুটি হয়েছে কিনা তা পরীক্ষা করার জন্য:

import random

b = benchmark([f7, iteration_utilities_unique_everseen, more_itertools_unique_everseen, odict],
              {2**i: [random.randint(0, 2**(i-1)) for _ in range(2**i)] for i in range(1, 20)},
              'list size (lots of duplicates)')
b.plot()

এখানে চিত্র বর্ণনা লিখুন

এবং একটিতে কেবল একটি মান রয়েছে:

b = benchmark([f7, iteration_utilities_unique_everseen, more_itertools_unique_everseen, odict],
              {2**i: [1]*(2**i) for i in range(1, 20)},
              'list size (only duplicates)')
b.plot()

এখানে চিত্র বর্ণনা লিখুন

এই সমস্ত ক্ষেত্রে iteration_utilities.unique_everseenফাংশনটি সবচেয়ে দ্রুত (আমার কম্পিউটারে)।


এই iteration_utilities.unique_everseenফাংশনটি ইনপুটগুলিতেও অপ্রয়োজনীয় মানগুলি পরিচালনা করতে পারে (তবে মানগুলি যখন হ্যাশযোগ্য হয় তবে O(n*n)পারফরম্যান্সের পরিবর্তে কোনও পারফরম্যান্স O(n)সহ)।

>>> lst = [{1}, {1}, {2}, {1}, {3}]

>>> list(unique_everseen(lst))
[{1}, {2}, {3}]

1 অস্বীকৃতি: আমি সেই প্যাকেজের লেখক।


এই লাইনটির জন্য প্রয়োজনীয়তাটি আমি বুঝতে পারি না: seen_add = seen.add- এটি কি মানদণ্ডগুলির জন্য প্রয়োজন?
অ্যালেক্স

@ অ্যালেক্স এটি এই উত্তরে প্রদত্ত পন্থা । এটি এটি জিজ্ঞাসা আরও বুদ্ধিমান হবে। সময়গুলির তুলনা করার জন্য আমি কেবলমাত্র উত্তর থেকে পন্থাটি ব্যবহার করেছি।
এমসিফার্ট

আপনি কি dict.fromkeys()আপনার লেখচিত্রটিতে পদ্ধতিটি যুক্ত করতে পারেন ?
বরিস

আমি শীঘ্রই সময়সীমার একই কাজ করতে পারি কিনা তা আমি নিশ্চিত নই। আপনি কি মনে করেন এটি এর চেয়ে অনেক দ্রুত ordereddict.fromkeys?
MSefert

6

মিজার্ডএক্স এর ভিত্তিতে কোনও হ্যাশযোগ্য ধরণের জন্য (যেমন তালিকার তালিকা):

def f7_noHash(seq)
    seen = set()
    return [ x for x in seq if str( x ) not in seen and not seen.add( str( x ) )]

3

nubতালিকাগুলির জন্য হাস্কেলের কার্যকারিতা নির্ধারণে ব্যবহৃত পুনরাবৃত্ত ধারণা ধার করা , এটি একটি পুনরাবৃত্তির উপায় হবে:

def unique(lst):
    return [] if lst==[] else [lst[0]] + unique(filter(lambda x: x!= lst[0], lst[1:]))

উদাহরণ:

In [118]: unique([1,5,1,1,4,3,4])
Out[118]: [1, 5, 4, 3]

আমি এটি বর্ধিত ডেটা আকারের জন্য চেষ্টা করেছিলাম এবং সাব-লিনিয়ার সময়-জটিলতা দেখেছি (চূড়ান্ত নয়, তবে প্রস্তাবিত এটি সাধারণ ডেটার জন্য ভাল হওয়া উচিত)।

In [122]: %timeit unique(np.random.randint(5, size=(1)))
10000 loops, best of 3: 25.3 us per loop

In [123]: %timeit unique(np.random.randint(5, size=(10)))
10000 loops, best of 3: 42.9 us per loop

In [124]: %timeit unique(np.random.randint(5, size=(100)))
10000 loops, best of 3: 132 us per loop

In [125]: %timeit unique(np.random.randint(5, size=(1000)))
1000 loops, best of 3: 1.05 ms per loop

In [126]: %timeit unique(np.random.randint(5, size=(10000)))
100 loops, best of 3: 11 ms per loop

আমি আরও আকর্ষণীয় মনে করি যে এটি অন্যান্য ক্রিয়াকলাপের দ্বারা স্বতন্ত্রতার সাথে সহজেই সাধারণীকরণ করা যায়। এটার মত:

import operator
def unique(lst, cmp_op=operator.ne):
    return [] if lst==[] else [lst[0]] + unique(filter(lambda x: cmp_op(x, lst[0]), lst[1:]), cmp_op)

উদাহরণস্বরূপ, আপনি কোনও ফাংশনে পাস করতে পারবেন যা একই পূর্ণসংখ্যার সাথে গোল করার ধারণাটি ব্যবহার করে যেমন এটি স্বতন্ত্রতার উদ্দেশ্যে "সমতা", যেমন:

def test_round(x,y):
    return round(x) != round(y)

তারপরে অনন্য (কিছু_ তালিকা, টেস্ট_গ্রাউন্ড) তালিকার অনন্য উপাদান সরবরাহ করবে যেখানে স্বতন্ত্রতা আর traditionalতিহ্যগত সমতা বলে বোঝায় না (যা এই সমস্যার সাথে সেট-ভিত্তিক বা ডিক-কী-ভিত্তিক পদ্ধতির কোনও ধরণের ব্যবহার দ্বারা বোঝানো হয়) তবে তার পরিবর্তে গ্রহণ করা প্রতিটি সম্ভাব্য পূর্ণসংখ্যক কে এর জন্য কে কে গোল করে কেবল প্রথম উপাদান যা উপাদানগুলির মধ্যে গোল হতে পারে, যেমন:

In [6]: unique([1.2, 5, 1.9, 1.1, 4.2, 3, 4.8], test_round)
Out[6]: [1.2, 5, 1.9, 4.2, 3]

1
নোট করুন যে অনন্য উপাদানের সংখ্যা যখন উপাদানের মোট সংখ্যার তুলনায় খুব বড় হয় তখন কার্য সম্পাদন খারাপ হয়ে যায়, যেহেতু প্রতিটি ধারাবাহিক পুনরাবৃত্ত কলের ব্যবহার filterসবেমাত্র পূর্ববর্তী কল থেকে উপকার পাবেন। তবে যদি অ্যারের আকারের তুলনায় অনন্য উপাদানের সংখ্যা ছোট হয় তবে এটি বেশ ভালভাবে সম্পাদন করা উচিত।
এলী

3

5 এক্স দ্রুত বৈকল্পিক হ্রাস কিন্তু আরও পরিশীলিত

>>> l = [5, 6, 6, 1, 1, 2, 2, 3, 4]
>>> reduce(lambda r, v: v in r[1] and r or (r[0].append(v) or r[1].add(v)) or r, l, ([], set()))[0]
[5, 6, 1, 2, 3, 4]

ব্যাখ্যা:

default = (list(), set())
# use list to keep order
# use set to make lookup faster

def reducer(result, item):
    if item not in result[1]:
        result[0].append(item)
        result[1].add(item)
    return result

>>> reduce(reducer, l, default)[0]
[5, 6, 1, 2, 3, 4]

3

এটি '_ [1]' প্রতীক দ্বারা নির্মিত হওয়ায় আপনি একটি তালিকা বোধগম্যতার উল্লেখ করতে পারেন।
উদাহরণস্বরূপ, নিম্নলিখিত ক্রিয়াকলাপটি তালিকার বোধগম্যতা উল্লেখ করে ক্রম পরিবর্তন না করে উপাদানগুলির একটি তালিকা অনন্য-আইফিজ করে।

def unique(my_list): 
    return [x for x in my_list if x not in locals()['_[1]']]

ডেমো:

l1 = [1, 2, 3, 4, 1, 2, 3, 4, 5]
l2 = [x for x in l1 if x not in locals()['_[1]']]
print l2

আউটপুট:

[1, 2, 3, 4, 5]

2
এছাড়াও মনে রাখবেন যে এটি এটিকে একটি ও (এন ^ 2) অপারেশন করে তুলবে, যেখানে একটি সেট / ডিক তৈরি করা (যা ধীরে ধীরে সময় অবলম্বন করে) এবং কেবল আগে দেখা যায় না এমন উপাদান যুক্ত করা লিনিয়ার হবে।
ইপি

এটি পাইথন ২.6 কেবলমাত্র আমি বিশ্বাস করি। এবং হ্যাঁ এটি ও (এন ^ 2)
জামিলাক

2

মিজার্ডএক্স এর উত্তর একাধিক পদ্ধতির ভাল সংগ্রহ দেয়।

উচ্চস্বরে ভাবতে ভাবতে আমি এটাই নিয়ে এসেছি:

mylist = [x for i,x in enumerate(mylist) if x not in mylist[i+1:]]

আপনার সমাধানটি দুর্দান্ত, তবে এটি প্রতিটি উপাদানটির শেষ চেহারা নেয়। প্রথম উপস্থিতিটি ব্যবহার করতে: [এক্স এর জন্য, গণিতে এক্স (মাইলিস্ট) যদি x মাইলিস্টে না থাকে [: i]]
রিভকা

7
যেহেতু তালিকায় অনুসন্ধান করা একটি O(n)অপারেশন এবং আপনি এটি প্রতিটি আইটেমটিতে সম্পাদন করেন, ফলে আপনার সমাধানের জটিলতা হবে O(n^2)। এ জাতীয় তুচ্ছ সমস্যার জন্য এটি কেবল অগ্রহণযোগ্য।
নিকিতা ভোলকভ

2

এটি করার একটি সহজ উপায় এখানে:

list1 = ["hello", " ", "w", "o", "r", "l", "d"]
sorted(set(list1 ), key=lambda x:list1.index(x))

যে আউটপুট দেয়:

["hello", " ", "w", "o", "r", "l", "d"]

1

আপনি কুরুচিপূর্ণ তালিকা বোঝার হ্যাক এক ধরণের করতে পারে।

[l[i] for i in range(len(l)) if l.index(l[i]) == i]

পছন্দ i,e in enumerate(l)করার l[i] for i in range(len(l))
ইভপোক

1

এর সাথে অপেক্ষাকৃত কার্যকর পদ্ধতির _sorted_একটি numpyঅ্যারে:

b = np.array([1,3,3, 8, 12, 12,12])    
numpy.hstack([b[0], [x[0] for x in zip(b[1:], b[:-1]) if x[0]!=x[1]]])

আউটপুট:

array([ 1,  3,  8, 12])

1
l = [1,2,2,3,3,...]
n = []
n.extend(ele for ele in l if ele not in set(n))

একটি জেনারেটর এক্সপ্রেশন যা ও (1) ব্যবহার করে একটি সেটটিকে নতুন তালিকায় কোনও উপাদান অন্তর্ভুক্ত করবে কিনা তা নির্ধারণের জন্য সন্ধান করে।


1
extendজেনারেটর এক্সপ্রেশন সহ চতুর ব্যবহার যা জিনিসটি প্রসারিত হওয়ার উপর নির্ভর করে (সুতরাং +1), তবে set(n)প্রতিটি পর্যায়ে পুনরায় সংশোধন করা হয় (যা লিনিয়ার) এবং এটি চতুর্ভুজ হওয়ার সামগ্রিক পদ্ধতির বাধা দেয়। বস্তুত, এই কেবল ব্যবহার না করে প্রায় অবশ্যই খারাপ ele in n। একক সদস্যপদ পরীক্ষার জন্য একটি সেট তৈরি করা সেট তৈরি ব্যয়ের পক্ষে উপযুক্ত নয়। তবুও - এটি একটি আকর্ষণীয় পদ্ধতির।
জন কোলেম্যান


1

ক্রমানুসারে সদৃশ মানগুলি নির্মূল করা, তবে অবশিষ্ট আইটেমগুলির ক্রম সংরক্ষণ করুন। সাধারণ উদ্দেশ্যে জেনারেটর ফাংশন ব্যবহার।

# for hashable sequence
def remove_duplicates(items):
    seen = set()
    for item in items:
        if item not in seen:
            yield item
            seen.add(item)

a = [1, 5, 2, 1, 9, 1, 5, 10]
list(remove_duplicates(a))
# [1, 5, 2, 9, 10]



# for unhashable sequence
def remove_duplicates(items, key=None):
    seen = set()
    for item in items:
        val = item if key is None else key(item)
        if val not in seen:
            yield item
            seen.add(val)

a = [ {'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 1, 'y': 2}, {'x': 2, 'y': 4}]
list(remove_duplicates(a, key=lambda d: (d['x'],d['y'])))
# [{'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 2, 'y': 4}]

0

আপনার যদি একটি লাইনারের প্রয়োজন হয় তবে সম্ভবত এটি সহায়তা করবে:

reduce(lambda x, y: x + y if y[0] not in x else x, map(lambda x: [x],lst))

... কাজ করা উচিত তবে আমি ভুল হলে আমাকে সংশোধন করা উচিত



0

আপনি যদি নিয়মিত ব্যবহার করেন pandas, এবং পারফরম্যান্সের তুলনায় নান্দনিকতা পছন্দ করা হয় তবে বিল্ট-ইন ফাংশনটি বিবেচনা করুন pandas.Series.drop_duplicates:

    import pandas as pd
    import numpy as np

    uniquifier = lambda alist: pd.Series(alist).drop_duplicates().tolist()

    # from the chosen answer 
    def f7(seq):
        seen = set()
        seen_add = seen.add
        return [ x for x in seq if not (x in seen or seen_add(x))]

    alist = np.random.randint(low=0, high=1000, size=10000).tolist()

    print uniquifier(alist) == f7(alist)  # True

টাইমিং:

    In [104]: %timeit f7(alist)
    1000 loops, best of 3: 1.3 ms per loop
    In [110]: %timeit uniquifier(alist)
    100 loops, best of 3: 4.39 ms per loop

0

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

def deduplicate(l):
    count = {}
    (read,write) = (0,0)
    while read < len(l):
        if l[read] in count:
            read += 1
            continue
        count[l[read]] = True
        l[write] = l[read]
        read += 1
        write += 1
    return l[0:write]

0

আমদানি করা মডিউল বা সেট ব্যবহার না করেই একটি সমাধান:

text = "ask not what your country can do for you ask what you can do for your country"
sentence = text.split(" ")
noduplicates = [(sentence[i]) for i in range (0,len(sentence)) if sentence[i] not in sentence[:i]]
print(noduplicates)

আউটপুট দেয়:

['ask', 'not', 'what', 'your', 'country', 'can', 'do', 'for', 'you']

এটি হ'ল ও (এন ** 2) জটিলতা + তালিকা প্রতিবার স্লাইসিং।
জিন-ফ্রান্সোইস ফ্যাব্রে

0

একটি স্থান মধ্যে পদ্ধতি

এই পদ্ধতিটি চতুর্ভুজযুক্ত, কারণ তালিকার প্রতিটি উপাদানগুলির জন্য তালিকায় আমরা একটি রৈখিক অনুসন্ধান করে থাকি (এর কারণে আমাদের তালিকাটি পুনরায় সাজানোর জন্য ব্যয় যুক্ত করতে হবে del)।

এটি বলেছে যে, যদি আমরা তালিকার শেষ থেকে শুরু করি এবং তার বামে উপ-তালিকার উপস্থিত প্রতিটি পদকে অপসারণের মূল দিকে এগিয়ে যাই তবে এটি জায়গায় কাজ করা সম্ভব said

কোডে এই ধারণাটি সহজভাবে

for i in range(len(l)-1,0,-1): 
    if l[i] in l[:i]: del l[i] 

বাস্তবায়নের একটি সাধারণ পরীক্ষা

In [91]: from random import randint, seed                                                                                            
In [92]: seed('20080808') ; l = [randint(1,6) for _ in range(12)] # Beijing Olympics                                                                 
In [93]: for i in range(len(l)-1,0,-1): 
    ...:     print(l) 
    ...:     print(i, l[i], l[:i], end='') 
    ...:     if l[i] in l[:i]: 
    ...:          print( ': remove', l[i]) 
    ...:          del l[i] 
    ...:     else: 
    ...:          print() 
    ...: print(l)
[6, 5, 1, 4, 6, 1, 6, 2, 2, 4, 5, 2]
11 2 [6, 5, 1, 4, 6, 1, 6, 2, 2, 4, 5]: remove 2
[6, 5, 1, 4, 6, 1, 6, 2, 2, 4, 5]
10 5 [6, 5, 1, 4, 6, 1, 6, 2, 2, 4]: remove 5
[6, 5, 1, 4, 6, 1, 6, 2, 2, 4]
9 4 [6, 5, 1, 4, 6, 1, 6, 2, 2]: remove 4
[6, 5, 1, 4, 6, 1, 6, 2, 2]
8 2 [6, 5, 1, 4, 6, 1, 6, 2]: remove 2
[6, 5, 1, 4, 6, 1, 6, 2]
7 2 [6, 5, 1, 4, 6, 1, 6]
[6, 5, 1, 4, 6, 1, 6, 2]
6 6 [6, 5, 1, 4, 6, 1]: remove 6
[6, 5, 1, 4, 6, 1, 2]
5 1 [6, 5, 1, 4, 6]: remove 1
[6, 5, 1, 4, 6, 2]
4 6 [6, 5, 1, 4]: remove 6
[6, 5, 1, 4, 2]
3 4 [6, 5, 1]
[6, 5, 1, 4, 2]
2 1 [6, 5]
[6, 5, 1, 4, 2]
1 5 [6]
[6, 5, 1, 4, 2]

In [94]:                                                                                                                             

পোস্ট করার আগে আমি 'স্থান' এর জন্য উত্তরগুলির বডিটি কোনও কাজে লাগেনি। অন্যরা যদি সমস্যাটি একইভাবে সমাধান করে থাকে তবে দয়া করে আমাকে সতর্ক করুন এবং আমি আমার উত্তরটি যথাযথভাবে সরিয়ে দেব।
gboffi

আপনি কেবল l[:] = <one of the the faster methods>কোনও জায়গাটিতে অপারেশন চাইলে ব্যবহার করতে পারেন, না?
টিমজেব

@ টিটিজেব হ্যাঁ এবং না ... যখন আমি a=[1]; b=a; a[:]=[2]তখন b==[2]মূল্যবোধ করি Trueএবং আমরা বলতে পারি যে আমরা এটি যথাস্থানে করছি, তবুও আপনি যা প্রস্তাব করেন তা নতুন স্থানের জন্য নতুন স্থান ব্যবহার করছে, নতুন ডেটা দিয়ে পুরানো ডেটা প্রতিস্থাপন করবে এবং চিহ্নিত করবে আবর্জনা সংগ্রহের জন্য পুরানো ডেটা কারণ কোনও কিছুই দ্বারা রেফারেন্স করা হয় না, তাই এটি জায়গায় জায়গায় কাজ করা বলাই ধারণাটি আঁকানো সামান্য কিছুটা যা আমি দেখিয়েছি এটি সম্ভব ... এটি কী অক্ষম? হ্যাঁ, তবে আমি আগে থেকেই বলেছি।
gboffi

0

zmk এর পদ্ধতির তালিকার বোঝাপড়া ব্যবহার করে যা খুব দ্রুত, তবুও স্বাভাবিকভাবে অর্ডারটি রাখে। সংবেদনশীল স্ট্রিংয়ের ক্ষেত্রে প্রয়োগ করার জন্য এটি সহজেই সংশোধন করা যেতে পারে। এটি আসল কেসটিও সংরক্ষণ করে।

def DelDupes(aseq) :
    seen = set()
    return [x for x in aseq if (x.lower() not in seen) and (not seen.add(x.lower()))]

নিবিড়ভাবে সম্পর্কিত ফাংশনগুলি হ'ল:

def HasDupes(aseq) :
    s = set()
    return any(((x.lower() in s) or s.add(x.lower())) for x in aseq)

def GetDupes(aseq) :
    s = set()
    return set(x for x in aseq if ((x.lower() in s) or s.add(x.lower())))

0

পান্ডাস ব্যবহারকারীদের চেক আউট করা উচিত pandas.unique

>>> import pandas as pd
>>> lst = [1, 2, 1, 3, 3, 2, 4]
>>> pd.unique(lst)
array([1, 2, 3, 4])

ফাংশন একটি NumPy অ্যারে প্রদান করে। প্রয়োজনে, আপনি এটিকে tolistপদ্ধতি সহ তালিকায় রূপান্তর করতে পারেন ।


0

একটি লাইনার তালিকা অনুধাবন:

values_non_duplicated = [value for index, value in enumerate(values) if value not in values[ : index]]

কেবলমাত্র শর্তসাপেক্ষে যুক্ত করুন যে মানটি আগের অবস্থানে নেই check

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