किसी सूची से यादृच्छिक तत्व को पॉप करने का सबसे पाइथोनिक तरीका क्या है?


90

कहो कि मेरे पास एक सूची है xजिसमें अनकाउन्ट लंबाई है जिसमें से मैं एक तत्व को बेतरतीब ढंग से पॉप करना चाहता हूं ताकि सूची में बाद में तत्व शामिल न हो। ऐसा करने का सबसे पाइथोनिक तरीका क्या है?

मैं की एक नहीं बल्कि असुविधाजनक combincation का उपयोग कर ऐसा कर सकते हैं pop, random.randintऔर len, और कम या अच्छे समाधान देखना चाहेंगे:

import random
x = [1,2,3,4,5,6]
x.pop(random.randint(0,len(x)-1))

मैं जो हासिल करने की कोशिश कर रहा हूं वह लगातार सूची से यादृच्छिक तत्वों को पॉप करता है। (यानी, बेतरतीब ढंग से एक तत्व पॉप और एक शब्दकोश में ले जाएँ, बेतरतीब ढंग से एक और तत्व पॉप और इसे दूसरे शब्दकोश में स्थानांतरित करें, ...)

ध्यान दें कि मैं पायथन 2.6 का उपयोग कर रहा हूं और खोज फ़ंक्शन के माध्यम से कोई समाधान नहीं मिला।


3
मैं पाइथोनिस्टा की बहुत नहीं हूं, लेकिन यह निश्चित रूप से मुझे बहुत अच्छा लगता है।
मैट बॉल

मेरे द्वारा एक विस्तृत समय जटिलता विश्लेषण किया गया है, सड़क के नीचे कहीं मेरा जवाब देखें। SHUFFLE प्रभावी नहीं है! लेकिन आप अभी भी उपयोग कर सकते हैं यदि आपको किसी तरह वस्तुओं का क्रम बदलने की आवश्यकता है। यदि पॉप (0) आपको चिंतित करता है, तो मेरे विश्लेषण में उल्लिखित डीक्यू का उपयोग करें।
निखिल स्वामी

लिखित उत्तर के लिए O (2) समय जटिलता। त्वरित उपयोग के लिए इसे एक फंक्शन में लपेटें। कृपया ध्यान दें कि list.pop (-1) के अलावा कोई भी सूची। pop (n) O (n) लेता है।
निखिल स्वामी

जवाबों:


95

क्या आप पहली जगह में बहुत Pythonic नहीं लग रहे हो लगता है। आपको सूची के बीच से सामान नहीं निकालना चाहिए, क्योंकि सूचियाँ उन सभी पायथन कार्यान्वयनों में सरणियों के रूप में कार्यान्वित की जाती हैं जिनके बारे में मुझे पता है, इसलिए यह एक O(n)ऑपरेशन है।

यदि आपको एल्गोरिथ्म के हिस्से के रूप में वास्तव में इस कार्यक्षमता की आवश्यकता है, तो आपको एक डेटा संरचना की जांच करनी चाहिए जैसे blistकि बीच से कुशल विलोपन का समर्थन करता है।

शुद्ध पायथन में, आप क्या कर सकते हैं यदि आपको शेष तत्वों तक पहुंच की आवश्यकता नहीं है, बस सूची को पहले फेरबदल करें और उसके बाद इसे पुन: व्यवस्थित करें:

lst = [1,2,3]
random.shuffle(lst)
for x in lst:
  # ...

यदि आपको वास्तव में शेष की आवश्यकता है (जो कि कोड गंध, आईएमएचओ का एक सा है), तो कम से कम आप pop()सूची के अंत से अब (जो तेज है!) कर सकते हैं।

while lst:
  x = lst.pop()
  # do something with the element      

सामान्य तौर पर, आप अक्सर अपने कार्यक्रमों को अधिक सुरुचिपूर्ण ढंग से व्यक्त कर सकते हैं यदि आप उत्परिवर्ती राज्य के बजाय एक अधिक कार्यात्मक शैली का उपयोग करते हैं (जैसे आप सूची के साथ करते हैं)।


3
तो एक बेहतर (तेज) विचार का उपयोग करना होगा random.shuffle(x)और फिर x.pop()? मुझे समझ में नहीं आ रहा है कि यह "कार्यात्मक" कैसे करें?
हेनरिक

1
@ हेनरिक: यदि आपके पास दो संग्रह हैं (उदाहरण के लिए, शब्दकोशों की एक सूची और यादृच्छिक संख्याओं की एक सूची) और आप उन्हें एक ही समय में क्रमबद्ध करना चाहते हैं, तो आप zipउन्हें (तानाशाही, संख्या) जोड़े की सूची प्राप्त कर सकते हैं। आपने कई शब्दकोशों के बारे में कुछ कहा, जिनमें से प्रत्येक को आप एक यादृच्छिक संख्या के साथ जोड़ना चाहते हैं। zipइस के लिए एकदम सही है
निकल्स बी।

2
जब मैं डाउन-वोट करता हूं तो मुझे एक पोस्ट जोड़ना चाहिए। ऐसे समय होते हैं जब आपको किसी सूची में से किसी आइटम को निकालने की आवश्यकता होती है ... मुझे इसे अभी करना होगा। कोई विकल्प नहीं: मेरे पास एक आदेशित सूची है, मुझे बीच में एक आइटम को निकालना होगा। यह बेकार है, लेकिन केवल अन्य विकल्प एक अर्ध-दुर्लभ ऑपरेशन के लिए एक भारी कोड रीफैक्टरिंग करना है। मुद्दा [] के कार्यान्वयन में से एक है, जो इस तरह के संचालन के लिए कुशल होना चाहिए, लेकिन ऐसा नहीं है।
मार्क गेरोलिमेटोस

5
@NiklasB। ओपी एक उदाहरण के रूप में यादृच्छिक का उपयोग कर रहा था (स्पष्ट रूप से, इसे छोड़ दिया जाना चाहिए था, इसने इस मुद्दे को बादल दिया)। "ऐसा मत करो" अपर्याप्त है। पायथन डेटा संरचना का सुझाव देने के लिए एक बेहतर उत्तर यह होगा कि SUFFICIENT एक्सेस स्पीड प्रदान करते समय ऐसे कार्यों का समर्थन करता है (स्पष्ट रूप से arra ... er ... सूची के रूप में अच्छा नहीं है)। अजगर 2 में, मुझे एक नहीं मिला। अगर मैं करता हूं, तो मैं इसका जवाब दूंगा। ध्यान दें कि ब्राउज़र की गड़बड़ी के कारण, मैं इसे अपनी मूल टिप्पणी में जोड़ने में असमर्थ था, मुझे एक द्वितीयक टिप्पणी जोड़नी चाहिए थी। मुझे ईमानदार रखने के लिए धन्यवाद :)
मार्क जेरोलीमाटोस

1
@MarkGerolimatos मानक पुस्तकालय में कुशल यादृच्छिक अभिगम और डालने / हटाने दोनों के साथ कोई डेटा संरचना नहीं है। आप शायद pypi.python.org/pypi/blist जैसी किसी चीज़ का उपयोग करना चाहते हैं, फिर भी मैं यह तर्क दूंगा कि बहुत सारे उपयोग के मामलों में इससे बचा जा सकता है
Niklas B.

51

आपको इससे बहुत बेहतर नहीं मिलेगा, लेकिन यहाँ एक मामूली सुधार है:

x.pop(random.randrange(len(x)))

पर प्रलेखन random.randrange():

random.randrange ([start], stop [, step])
बेतरतीब ढंग से चयनित तत्व से लौटें range(start, stop, step)। यह बराबर है choice(range(start, stop, step)), लेकिन वास्तव में एक सीमा वस्तु का निर्माण नहीं करता है।


14

यदि सूची के बाकी तत्वों का क्रम मायने नहीं रखता है, तो किसी सूची में से किसी एक तत्व को यादृच्छिक सूची में निकालने के लिए:

import random

L = [1,2,3,4,5,6]
i = random.randrange(len(L)) # get random index
L[i], L[-1] = L[-1], L[i]    # swap with the last element
x = L.pop()                  # pop last element O(1)

स्वैप का उपयोग किसी सूची के मध्य से हटाए जाने पर O (n) व्यवहार से बचने के लिए किया जाता है।


9

यहां एक और विकल्प है: आप पहले सूची में फेरबदल क्यों नहीं करते हैं , और तब तक इसके तत्वों को पॉप करना शुरू कर देते हैं जब तक कि कोई और तत्व नहीं रहते? इस तरह:

import random

x = [1,2,3,4,5,6]
random.shuffle(x)

while x:
    p = x.pop()
    # do your stuff with p

3
@NiklasB। क्योंकि हम सूची से तत्वों को निकाल रहे हैं। यदि तत्वों को निकालना बिल्कुल आवश्यक नहीं है, तो हाँ मैं आपसे सहमत हूँ:[for p in x]
óscar López

क्योंकि यह सूची को बदल देता है और यदि आप अभी आधे तत्वों का चयन करना चाहते हैं और दूसरा आधा बाद में, तो आपके पास शेष सेट बाद में होगा।
हेनरिक

@ हेनरिक: ठीक है, इसलिए मैंने आपसे पूछा है कि क्या आपको शेष सूची की आवश्यकता है। आपने इसका जवाब नहीं दिया।
निकल्स बी।

2

इसका एक तरीका यह है:

x.remove(random.choice(x))

7
यह समस्याग्रस्त हो सकता है यदि तत्व एक बार अधिक हो जाते हैं।
निकल्स बी।

2
डुप्लिकेट होने पर यह सबसे बाईं ओर के तत्व को हटा देगा, जिससे पूरी तरह से यादृच्छिक परिणाम नहीं होगा।
फोगबर्ड

साथ popआप इस आप नहीं कर सकते के साथ निकाली गई तत्व पर एक नाम इंगित कर सकते हैं,।
एएफएफ

पर्याप्त रूप से, मैं मानता हूं कि यह बहुत यादृच्छिक नहीं है जब तत्व एक से अधिक बार होते हैं।
शिमोन विसर

1
अपने वितरण को तिरछा करने के प्रश्न के अलावा, removeसूची के रैखिक स्कैन की आवश्यकता होती है। सूचकांक को देखने की तुलना में यह बहुत ही अयोग्य है।
अपरोनस्टरलिंग

2

सूची से पॉपिंग न करते हुए, मैंने डुप्लिकेट के बिना सूची से X यादृच्छिक आइटम प्राप्त करने का प्रयास करते समय Google पर इस प्रश्न का सामना किया। यहाँ मैं आखिरकार इस्तेमाल किया है:

items = [1, 2, 3, 4, 5]
items_needed = 2
from random import shuffle
shuffle(items)
for item in items[:items_needed]:
    print(item)

यह पूरी तरह से अक्षम हो सकता है क्योंकि आप पूरी सूची में फेरबदल कर रहे हैं, लेकिन केवल इसके एक छोटे से हिस्से का उपयोग कर रहे हैं, लेकिन मैं एक अनुकूलन विशेषज्ञ नहीं हूं, इसलिए मैं गलत हो सकता हूं।


3
random.sample(items, items_needed)
jfs

2

मुझे पता है कि यह एक पुराना सवाल है, लेकिन सिर्फ प्रलेखन के लिए:

यदि आप (एक ही प्रश्न को देखने वाला व्यक्ति) वही कर रहे हैं जो मुझे लगता है कि आप कर रहे हैं, जो कि सूची में से यादृच्छिक रूप से आइटमों की संख्या का चयन कर रहा है (जहां k <= len (आपका सूची)), लेकिन यह सुनिश्चित करना कि प्रत्येक आइटम का चयन कभी अधिक नहीं किया जाता है एक समय से अधिक (= प्रतिस्थापन के बिना नमूना), आप यादृच्छिक का उपयोग कर सकते हैं । @ jf-sebastian की तरह पता चलता है। लेकिन उपयोग के मामले के बारे में अधिक जानने के बिना, मुझे नहीं पता कि यह वही है जो आपको चाहिए।


2

कई जवाबों के उपयोग के बावजूद random.shuffle(x)और x.pop()बड़े डेटा पर इसकी बहुत धीमी गति से। और जब फेरबदल सक्षम किया जाता है, तब 10000तत्वों की सूची के लिए आवश्यक समय लगता 6 secondsहै। जब फेरबदल अक्षम गति थी0.2s

ऊपर दी गई सभी विधियों का परीक्षण करने के बाद सबसे तेज़ विधि @jfs द्वारा लिखी गई थी

import random

L = ['1',2,3,'4'...1000] #you can take mixed or pure list
i = random.randrange(len(L)) # get random index
L[i], L[-1] = L[-1], L[i]    # swap with the last element
x = L.pop()                  # pop last element O(1)

मेरे दावे के समर्थन में इस स्रोत से समय जटिलता चार्ट है यहाँ छवि विवरण दर्ज करें


यदि सूची में कोई डुप्लिकेट नहीं हैं,

आप सेट का उपयोग करके भी अपना उद्देश्य प्राप्त कर सकते हैं। एक बार सेट डुप्लिकेट में बनाई गई सूची हटा दी जाएगी। remove by valueऔर remove randomलागत O(1), यानी बहुत ही आकर्षक। यह सबसे साफ तरीका है जिसके साथ मैं आ सकता हूं।

L=set([1,2,3,4,5,6...]) #directly input the list to inbuilt function set()
while 1:
    r=L.pop()
    #do something with r , r is random element of initial list L.

listsसमर्थन A+Bविकल्प के विपरीत , साथ में setsभी समर्थन और । सुपर उपयोगी जब आप डेटा पर तार्किक संचालन करना चाहते हैं।A-B (A minus B)A+B (A union B)A.intersection(B,C,D)


ऐच्छिक

यदि आप गति चाहते हैं, जब ऑपरेशन सिर और पूंछ की सूची पर किया जाता है, तो मेरे दावे के समर्थन में यहां अजगर चित्रण (डबल समाप्त कतार) का उपयोग करें। एक छवि हजार शब्दों की है।

यहाँ छवि विवरण दर्ज करें


1

यह जवाब @ निक्लास-बी के सौजन्य से आता है :

" आप शायद pypi.python.org/pypi/blist जैसे कुछ का उपयोग करना चाहते हैं "

PYPI पृष्ठ को उद्धृत करने के लिए :

... बेहतर अस्मितावादी प्रदर्शन के साथ एक सूची-प्रकार और छोटी सूचियों पर समान प्रदर्शन

ब्लिस्ट पायथन सूची के लिए एक ड्रॉप-इन प्रतिस्थापन है जो बड़ी सूचियों को संशोधित करते समय बेहतर प्रदर्शन प्रदान करता है। ब्लिस्ट पैकेज में सॉर्टलिस्ट, सॉर्टसेट, वेकसोर्ड लिस्ट, वीकसेरसेट, सॉर्टेडडिक्ट और बीटूपल प्रकार भी प्रदान करता है।

एक रैंडम एक्सेस / रैंडम रन एंड पर कम प्रदर्शन को मान लेगा , क्योंकि यह एक "कॉपी ऑन राइट" डेटा स्ट्रक्चर है। यह पायथन सूचियों पर कई उपयोग मामलों की धारणाओं का उल्लंघन करता है, इसलिए इसका उपयोग सावधानी से करें

फिर भी, यदि आपका मुख्य उपयोग मामला किसी सूची के साथ कुछ अजीब और अप्राकृतिक करने के लिए है (जैसा कि @OP द्वारा दिए गए मजबूर उदाहरण में, या मेरे पायथन 2.6 फीफो कतार-दर-दर-मुद्दे के साथ), तो यह बिल अच्छी तरह से फिट होगा ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.