python आप सूची को समान आकार के टुकड़ों में कैसे विभाजित करते हैं?
मेरे पास मनमानी लंबाई की एक सूची है, और मुझे इसे बराबर आकार के हिस्सों में विभाजित करने और उस पर काम करने की आवश्यकता है। ऐसा करने के कुछ स्पष्ट तरीके हैं, जैसे काउंटर और दो सूचियां रखना, और जब दूसरी सूची भर जाती है, तो इसे पहली सूची में जोड़ें और डेटा के अगले दौर के लिए दूसरी सूची खाली करें, लेकिन यह संभावित रूप से बेहद महंगा है।
मैं सोच रहा था कि किसी के पास किसी भी लंबाई की सूचियों के लिए इसका अच्छा समाधान था, उदाहरण के लिए जनरेटर का उपयोग करना।
मैं itertools
में कुछ उपयोगी खोज रहा था लेकिन मुझे कुछ भी स्पष्ट रूप से उपयोगी नहीं मिला। हालांकि, इसे याद किया हो सकता है।
संबंधित प्रश्न: भाग में एक सूची में फिर से शुरू करने के लिए सबसे अधिक "पायथनिक" तरीका क्या है?
मुझे पता है कि यह पुराना है लेकिन मुझे नहीं पता कि कोई भी numpy.array_split
उल्लेख नहीं numpy.array_split
:
lst = range(50)
In [26]: np.array_split(lst,5)
Out[26]:
[array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19]),
array([20, 21, 22, 23, 24, 25, 26, 27, 28, 29]),
array([30, 31, 32, 33, 34, 35, 36, 37, 38, 39]),
array([40, 41, 42, 43, 44, 45, 46, 47, 48, 49])]
मुझे आश्चर्य है कि किसी ने भी इसे दो-तर्क फ़ॉर्म का उपयोग करने का विचार नहीं किया है:
from itertools import islice
def chunk(it, size):
it = iter(it)
return iter(lambda: tuple(islice(it, size)), ())
डेमो:
>>> list(chunk(range(14), 3))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13)]
यह किसी भी पुनरावर्तनीय के साथ काम करता है और उत्पादन आलसी उत्पादन करता है। यह इटरेटर की बजाय tuples देता है, लेकिन मुझे लगता है कि यह एक निश्चित लालित्य है। यह पैड भी नहीं है; यदि आप पैडिंग चाहते हैं, तो उपर्युक्त पर एक साधारण भिन्नता पर्याप्त होगी:
from itertools import islice, chain, repeat
def chunk_pad(it, size, padval=None):
it = chain(iter(it), repeat(padval))
return iter(lambda: tuple(islice(it, size)), (padval,) * size)
डेमो:
>>> list(chunk_pad(range(14), 3))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, None)]
>>> list(chunk_pad(range(14), 3, 'a'))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, 'a')]
izip_longest
समाधान की तरह, उपरोक्त हमेशा पैड। जहां तक मुझे पता है, वैकल्पिक रूप से पैड के लिए कोई भी दो या दो-लाइन इटारेटोल्स नुस्खा नहीं है। उपर्युक्त दो दृष्टिकोणों को जोड़कर, यह बहुत करीब आता है:
_no_padding = object()
def chunk(it, size, padval=_no_padding):
if padval == _no_padding:
it = iter(it)
sentinel = ()
else:
it = chain(iter(it), repeat(padval))
sentinel = (padval,) * size
return iter(lambda: tuple(islice(it, size)), sentinel)
डेमो:
>>> list(chunk(range(14), 3))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13)]
>>> list(chunk(range(14), 3, None))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, None)]
>>> list(chunk(range(14), 3, 'a'))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, 'a')]
मेरा मानना है कि यह सबसे छोटा चंकर प्रस्तावित है जो वैकल्पिक पैडिंग प्रदान करता है।
सरल अभी तक सुरुचिपूर्ण
l = range(1, 1000)
print [l[x:x+10] for x in xrange(0, len(l), 10)]
या यदि आप पसंद करते हैं:
chunks = lambda l, n: [l[x: x+n] for x in xrange(0, len(l), n)]
chunks(l, 10)
यहां अन्य उत्तरों की आलोचना:
इनमें से कोई भी जवाब समान रूप से आकार के टुकड़े नहीं हैं, वे सभी अंत में एक रनट खंड छोड़ देते हैं, इसलिए वे पूरी तरह से संतुलित नहीं होते हैं। यदि आप काम को वितरित करने के लिए इन कार्यों का उपयोग कर रहे थे, तो आपने दूसरों के सामने अच्छी तरह से परिष्कृत होने की संभावना बनाई है, इसलिए यह कुछ भी करने के आसपास बैठेगा जबकि अन्य कड़ी मेहनत कर रहे थे।
उदाहरण के लिए, वर्तमान शीर्ष उत्तर के साथ समाप्त होता है:
[60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
[70, 71, 72, 73, 74]]
मैं बस अंत में उस दौड़ से नफरत करता हूँ!
अन्य, list(grouper(3, xrange(7)))
तरह list(grouper(3, xrange(7)))
, और chunk(xrange(7), 3)
दोनों वापसी: [(0, 1, 2), (3, 4, 5), (6, None, None)]
। None
सिर्फ पैडिंग नहीं है, बल्कि मेरी राय में सुरुचिपूर्ण है। वे समान रूप से reering नहीं कर रहे हैं।
हम इन्हें बेहतर क्यों नहीं विभाजित कर सकते हैं?
मेरा समाधान
यहां एक संतुलित समाधान है, जिसे मैंने उत्पादन में उपयोग किए गए फ़ंक्शन से अनुकूलित किया है ( range
साथ xrange
को प्रतिस्थापित करने के लिए पायथन 3 में नोट):
def baskets_from(items, maxbaskets=25):
baskets = [[] for _ in xrange(maxbaskets)] # in Python 3 use range
for i, item in enumerate(items):
baskets[i % maxbaskets].append(item)
return filter(None, baskets)
और मैंने एक जेनरेटर बनाया जो वही करता है यदि आप इसे एक सूची में डालते हैं:
def iter_baskets_from(items, maxbaskets=3):
'''generates evenly balanced baskets from indexable iterable'''
item_count = len(items)
baskets = min(item_count, maxbaskets)
for x_i in xrange(baskets):
yield [items[y_i] for y_i in xrange(x_i, item_count, baskets)]
और आखिरकार, चूंकि मैं देखता हूं कि उपर्युक्त सभी कार्य तत्वों को एक संगत क्रम में लौटाते हैं (जैसा कि उन्हें दिया गया था):
def iter_baskets_contiguous(items, maxbaskets=3, item_count=None):
'''
generates balanced baskets from iterable, contiguous contents
provide item_count if providing a iterator that doesn't support len()
'''
item_count = item_count or len(items)
baskets = min(item_count, maxbaskets)
items = iter(items)
floor = item_count // baskets
ceiling = floor + 1
stepdown = item_count % baskets
for x_i in xrange(baskets):
length = ceiling if x_i < stepdown else floor
yield [items.next() for _ in xrange(length)]
उत्पादन
उन्हें जांचने के लिए:
print(baskets_from(xrange(6), 8))
print(list(iter_baskets_from(xrange(6), 8)))
print(list(iter_baskets_contiguous(xrange(6), 8)))
print(baskets_from(xrange(22), 8))
print(list(iter_baskets_from(xrange(22), 8)))
print(list(iter_baskets_contiguous(xrange(22), 8)))
print(baskets_from('ABCDEFG', 3))
print(list(iter_baskets_from('ABCDEFG', 3)))
print(list(iter_baskets_contiguous('ABCDEFG', 3)))
print(baskets_from(xrange(26), 5))
print(list(iter_baskets_from(xrange(26), 5)))
print(list(iter_baskets_contiguous(xrange(26), 5)))
कौन सा प्रिंट आउट करता है:
[[0], [1], [2], [3], [4], [5]]
[[0], [1], [2], [3], [4], [5]]
[[0], [1], [2], [3], [4], [5]]
[[0, 8, 16], [1, 9, 17], [2, 10, 18], [3, 11, 19], [4, 12, 20], [5, 13, 21], [6, 14], [7, 15]]
[[0, 8, 16], [1, 9, 17], [2, 10, 18], [3, 11, 19], [4, 12, 20], [5, 13, 21], [6, 14], [7, 15]]
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12, 13, 14], [15, 16, 17], [18, 19], [20, 21]]
[['A', 'D', 'G'], ['B', 'E'], ['C', 'F']]
[['A', 'D', 'G'], ['B', 'E'], ['C', 'F']]
[['A', 'B', 'C'], ['D', 'E'], ['F', 'G']]
[[0, 5, 10, 15, 20, 25], [1, 6, 11, 16, 21], [2, 7, 12, 17, 22], [3, 8, 13, 18, 23], [4, 9, 14, 19, 24]]
[[0, 5, 10, 15, 20, 25], [1, 6, 11, 16, 21], [2, 7, 12, 17, 22], [3, 8, 13, 18, 23], [4, 9, 14, 19, 24]]
[[0, 1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15], [16, 17, 18, 19, 20], [21, 22, 23, 24, 25]]
ध्यान दें कि संगत जनरेटर अन्य लंबाई के समान लंबाई पैटर्न में भाग प्रदान करता है, लेकिन आइटम सभी क्रम में होते हैं, और वे समान रूप से विभाजित होते हैं क्योंकि कोई अलग तत्वों की सूची विभाजित कर सकता है।
उदाहरण के लिए यदि आपके पास 3 का खंड आकार था, तो आप यह कर सकते थे:
zip(*[iterable[i::3] for i in range(3)])
स्रोत: http://code.activestate.com/recipes/303060-group-a-list-into-sequential-n-tuples/
मैं इसका उपयोग तब करूंगा जब मेरा हिस्सा आकार निश्चित संख्या है, मैं टाइप कर सकता हूं, उदाहरण के लिए '3', और कभी नहीं बदलेगा।
जनरेटर अभिव्यक्ति:
def chunks(seq, n):
return (seq[i:i+n] for i in xrange(0, len(seq), n))
जैसे।
print list(chunks(range(1, 1000), 10))
इस बिंदु पर, मुझे लगता है कि हमें एक रिकर्सिव जनरेटर की आवश्यकता है, बस मामले में ...
पायथन 2 में:
def chunks(li, n):
if li == []:
return
yield li[:n]
for e in chunks(li[n:], n):
yield e
पायथन 3 में:
def chunks(li, n):
if li == []:
return
yield li[:n]
yield from chunks(li[n:], n)
इसके अलावा, भारी विदेशी आक्रमण के मामले में, एक सजाया गया रिकर्सिव जनरेटर आसान हो सकता है:
def dec(gen):
def new_gen(li, n):
for e in gen(li, n):
if e == []:
return
yield e
return new_gen
@dec
def chunks(li, n):
yield li[:n]
for e in chunks(li[n:], n):
yield e
आप utilspie
लाइब्रेरी के get_chunks
फ़ंक्शन का भी उपयोग कर सकते हैं:
>>> from utilspie import iterutils
>>> a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(iterutils.get_chunks(a, 5))
[[1, 2, 3, 4, 5], [6, 7, 8, 9]]
आप utilspie
माध्यम से utilspie
स्थापित कर सकते हैं:
sudo pip install utilspie
अस्वीकरण: मैं utilspie पुस्तकालय के निर्माता हूँ ।
मैं विभिन्न दृष्टिकोणों के प्रदर्शन के बारे में उत्सुक था और यहां यह है:
पायथन 3.5.1 पर परीक्षण किया
import time
batch_size = 7
arr_len = 298937
#---------slice-------------
print("\r\nslice")
start = time.time()
arr = [i for i in range(0, arr_len)]
while True:
if not arr:
break
tmp = arr[0:batch_size]
arr = arr[batch_size:-1]
print(time.time() - start)
#-----------index-----------
print("\r\nindex")
arr = [i for i in range(0, arr_len)]
start = time.time()
for i in range(0, round(len(arr) / batch_size + 1)):
tmp = arr[batch_size * i : batch_size * (i + 1)]
print(time.time() - start)
#----------batches 1------------
def batch(iterable, n=1):
l = len(iterable)
for ndx in range(0, l, n):
yield iterable[ndx:min(ndx + n, l)]
print("\r\nbatches 1")
arr = [i for i in range(0, arr_len)]
start = time.time()
for x in batch(arr, batch_size):
tmp = x
print(time.time() - start)
#----------batches 2------------
from itertools import islice, chain
def batch(iterable, size):
sourceiter = iter(iterable)
while True:
batchiter = islice(sourceiter, size)
yield chain([next(batchiter)], batchiter)
print("\r\nbatches 2")
arr = [i for i in range(0, arr_len)]
start = time.time()
for x in batch(arr, batch_size):
tmp = x
print(time.time() - start)
#---------chunks-------------
def chunks(l, n):
"""Yield successive n-sized chunks from l."""
for i in range(0, len(l), n):
yield l[i:i + n]
print("\r\nchunks")
arr = [i for i in range(0, arr_len)]
start = time.time()
for x in chunks(arr, batch_size):
tmp = x
print(time.time() - start)
#-----------grouper-----------
from itertools import zip_longest # for Python 3.x
#from six.moves import zip_longest # for both (uses the six compat library)
def grouper(iterable, n, padvalue=None):
"grouper(3, 'abcdefg', 'x') --> ('a','b','c'), ('d','e','f'), ('g','x','x')"
return zip_longest(*[iter(iterable)]*n, fillvalue=padvalue)
arr = [i for i in range(0, arr_len)]
print("\r\ngrouper")
start = time.time()
for x in grouper(arr, batch_size):
tmp = x
print(time.time() - start)
परिणाम:
slice
31.18285083770752
index
0.02184295654296875
batches 1
0.03503894805908203
batches 2
0.22681021690368652
chunks
0.019841909408569336
grouper
0.006506919860839844
कोड:
def split_list(the_list, chunk_size):
result_list = []
while the_list:
result_list.append(the_list[:chunk_size])
the_list = the_list[chunk_size:]
return result_list
a_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print split_list(a_list, 3)
परिणाम:
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
एक और अधिक स्पष्ट संस्करण।
def chunkList(initialList, chunkSize):
"""
This function chunks a list into sub lists
that have a length equals to chunkSize.
Example:
lst = [3, 4, 9, 7, 1, 1, 2, 3]
print(chunkList(lst, 3))
returns
[[3, 4, 9], [7, 1, 1], [2, 3]]
"""
finalList = []
for i in range(0, len(initialList), chunkSize):
finalList.append(initialList[i:i+chunkSize])
return finalList
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
CHUNK = 4
[a[i*CHUNK:(i+1)*CHUNK] for i in xrange((len(a) + CHUNK - 1) / CHUNK )]
def chunks(iterable,n):
"""assumes n is an integer>0
"""
iterable=iter(iterable)
while True:
result=[]
for i in range(n):
try:
a=next(iterable)
except StopIteration:
break
else:
result.append(a)
if result:
yield result
else:
break
g1=(i*i for i in range(10))
g2=chunks(g1,3)
print g2
'<generator object chunks at 0x0337B9B8>'
print list(g2)
'[[0, 1, 4], [9, 16, 25], [36, 49, 64], [81]]'
See this reference
>>> orange = range(1, 1001)
>>> otuples = list( zip(*[iter(orange)]*10))
>>> print(otuples)
[(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), ... (991, 992, 993, 994, 995, 996, 997, 998, 999, 1000)]
>>> olist = [list(i) for i in otuples]
>>> print(olist)
[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], ..., [991, 992, 993, 994, 995, 996, 997, 998, 999, 1000]]
>>>
Python3