सूची की समझ: प्रत्येक आइटम के लिए दो (या अधिक) आइटम लौटना


88

क्या सूची की समझ में प्रत्येक आइटम के लिए 2 (या अधिक) आइटम वापस करना संभव है?

मुझे क्या चाहिए (उदाहरण):

[f(x), g(x) for x in range(n)]

लौट जाना चाहिए [f(0), g(0), f(1), g(1), ..., f(n-1), g(n-1)]

तो, कोड के इस ब्लॉक को बदलने के लिए कुछ:

result = list()
for x in range(n):
    result.add(f(x))
    result.add(g(x))

3
जिज्ञासा से बाहर, आप ऐसा क्यों करना चाहते हैं? इस तरह से करने की कोशिश किए बिना अपने अंतिम लक्ष्य को प्राप्त करने का एक बेहतर तरीका हो सकता है।
murgatroid99 16

3
मुख्य रूप से क्योंकि मुझे कार्यात्मक प्रोग्रामिंग पसंद है। मैं निर्देशांक की सूची को pyglet.graphics.draw फ़ंक्शन के साथ उपयोग करने के लिए स्क्रीन निर्देशांक के एक टपल को मैप करना चाहता हूं।
हश्मश

जवाबों:


52
>>> from itertools import chain
>>> f = lambda x: x + 2
>>> g = lambda x: x ** 2
>>> list(chain.from_iterable((f(x), g(x)) for x in range(3)))
[2, 0, 3, 1, 4, 4]

समय:

from timeit import timeit

f = lambda x: x + 2
g = lambda x: x ** 2

def fg(x):
    yield f(x)
    yield g(x)

print timeit(stmt='list(chain.from_iterable((f(x), g(x)) for x in range(3)))',
             setup='gc.enable(); from itertools import chain; f = lambda x: x + 2; g = lambda x: x ** 2')

print timeit(stmt='list(chain.from_iterable(fg(x) for x in range(3)))',
             setup='gc.enable(); from itertools import chain; from __main__ import fg; f = lambda x: x + 2; g = lambda x: x ** 2')

print timeit(stmt='[func(x) for x in range(3) for func in (f, g)]',
             setup='gc.enable(); f = lambda x: x + 2; g = lambda x: x ** 2')


print timeit(stmt='list(chain.from_iterable((f(x), g(x)) for x in xrange(10**6)))',
             setup='gc.enable(); from itertools import chain; f = lambda x: x + 2; g = lambda x: x ** 2',
             number=20)

print timeit(stmt='list(chain.from_iterable(fg(x) for x in xrange(10**6)))',
             setup='gc.enable(); from itertools import chain; from __main__ import fg; f = lambda x: x + 2; g = lambda x: x ** 2',
             number=20)

print timeit(stmt='[func(x) for x in xrange(10**6) for func in (f, g)]',
             setup='gc.enable(); f = lambda x: x + 2; g = lambda x: x ** 2',
             number=20)

२.६९२१०७७७०९४

३.१३९००७८७८७४

१.६२४६१०७१९३२

२५.५९४४०५८२८७

२९.२६२३७११७९३

२५.७२११८४९२८६


4
यह कोड अनावश्यक ट्यूपल्स बनाता है (f(x), g(x))। बेहतर रूप में लिखा जा सकता है: def fg(x): yield x + 2; yield x ** 2; list(chain.from_iterable(fg(x) for x in range(3)))
khachik

1
आप इसे सामान्यीकृत भी कर सकते हैं chain.from_iterable((func(x) for func in funcs) for x in range(n)))। जो संयोगवश खटीक की शिकायत को खत्म कर देगा। (हालांकि एक अर्थ में, मेरी और उसकी प्रक्रिया के संदर्भ में अनिवार्य रूप से समान हैं। हम बस आंतरिक जनरेटर को अलग तरह से परिभाषित करते हैं।)
JAB

यह मेरे sum(..., [])उत्तर से बेहतर है, क्योंकि इसमें ओ (एन ^ 2) के प्रदर्शन के बजाय प्रत्येक (इस प्रकार ओ (एन) प्रदर्शन है) सूची को पुनः बनाने की आवश्यकता नहीं है। मैं sum(..., [])तब भी उपयोग करूंगा जब मैं एक त्वरित एक-लाइनर चाहता हूं या मैं जल्दी में हूं, या जब शब्दों की संख्या संयुक्त हो रही है (जैसे <= 10)।
Ninjagecko

@ शेखिक मुझे लगता है कि यह तेजी से होगा, लेकिन मैं दोनों तरीकों को अभी समय दूंगा, हालांकि अजगर में बहुत तेजी से ट्यूपल्स उत्पन्न होते हैं।
जामिलाक

3
एक तीसरा उत्तर, जो गायब हो गया, इस तरह दिखता था: [y for x in range(n) for y in (f(x), g(x))]लेकिन यह शायद धीमा है। @jamylak आप चाहें तो यह परीक्षण भी कर सकते हैं।
हश्मश

117

डबल सूची समझ:

[f(x) for x in range(5) for f in (f1,f2)]

डेमो:

>>> f1 = lambda x: x
>>> f2 = lambda x: 10*x

>>> [f(x) for x in range(5) for f in (f1,f2)]
[0, 0, 1, 10, 2, 20, 3, 30, 4, 40]

10
यह अच्छा है क्योंकि यह पता चलता है कि डबल सूची comps इतना डरावना नहीं हैं: वे बस लिखा छोरों के लिए नेस्ट कर रहे हैं बस छोरों के लिए की तरहfor x in range(5): for f in (f1, f2): newlist.append(f(x))। मैं उन्हें थोड़ा भ्रमित करता था क्योंकि मैं आदेश को उलटने की कोशिश करता रहा।
DSM

1
यह स्वीकृत उत्तर होना चाहिए, धन्यवाद, अद्भुत!
विंगजम

@ डीडीएम मुझे लगता है, यह हमेशा के लिए भ्रमित हो जाएगा।)
विनैंड

11
sum( ([f(x),g(x)] for x in range(n)), [] )

इसके बराबर है [f(1),g(1)] + [f(2),g(2)] + [f(3),g(3)] + ...

आप इसके बारे में भी सोच सकते हैं:

def flatten(list):
    ...

flatten( [f(x),g(x)] for x in ... )

नोट: सही तरीका यह है itertools.chain.from_iterableकि डबल लिस्ट का इस्तेमाल किया जाए । (इसे हर + पर सूची को फिर से बनाने की आवश्यकता नहीं है, इस प्रकार ओ (एन ^ 2) के प्रदर्शन के बजाय ओ (एन) प्रदर्शन है।) मैं अभी भी उपयोग करूंगा sum(..., [])जब मैं एक-एक लाइनर चाहता हूं या मैं जल्दी में हूं। , या जब शब्दों की संख्या को संयोजित किया जाता है, तो उदाहरण के लिए (जैसे <= 10)। यही कारण है कि मैं अभी भी यहाँ, इस चेतावनी के साथ इसका उल्लेख करता हूं। आप tuples का उपयोग भी कर सकते हैं: ((f(x),g(x)) for ...), ()(या khachik की टिप्पणी के अनुसार, एक जनरेटर fg (x) जो दो-टुपल पैदा करता है)।


@ArashThr: यह कर रहा है[f(1),g(1)] + [f(2),g(2)] + [f(3),g(3)] + ...
Ninjagecko

क्या आप बता सकते हैं कि यह वास्तव में क्या कर रहा है?
Rsh

नोट: इसमें O (N ^ 2) रनटाइम है इसलिए यह विशाल सूचियों पर धीमा हो सकता है।
जामिलक

1
@ जमैलाक: हां, मैंने टिप्पणियों में आपके जवाब पर इसका उल्लेख किया है। =)
नवजागेको

मैं sum()इस तरह से एक एंटीपैटर्न में गाली देने पर विचार करता हूं , और मुझे किसी भी परिस्थिति में इसका उपयोग करने का कोई औचित्य नहीं दिखता है। आपके अन्य उत्तर में कोड कम टाइपिंग है, इसलिए भी बहाना "जब मैं एक त्वरित एक-लाइनर चाहता हूं या मैं जल्दी में हूं" वास्तव में इसे काट नहीं करता है।
स्वेन मार्नाच

2

यह लंबोदर फ़ंक्शन एक ही सूची में दो सूचियाँ देता है:

zipped = lambda L1, L2: [L[i] 
                         for i in range(min(len(L1), len(L2))) 
                         for L in (L1, L2)]

उदाहरण:

>>> f = [x for x in range(5)]
>>> g = [x*10 for x in range(5)]
>>> zipped(f, g)
[0, 0, 1, 10, 2, 20, 3, 30, 4, 40]

1

मुझे पता है कि ओपी एक सूची समझ समाधान की तलाश में है, लेकिन मैं एक विकल्प का उपयोग करना चाहूंगा list.extend()

f = lambda x: x
g = lambda x: 10*x

result = []
extend = result.extend
for x in range(5):
    extend((f(x),g(x)))

जो कि डबल लिस्ट कॉम्प्रिहेंशन का उपयोग करने से थोड़ा तेज है।

nums = range(100000)

def double_comprehension():
    return [func(x) for x in nums for func in (f,g)]

def list_extend():
    result = []
    extend = result.extend
    for x in nums:
        extend((f(x),g(x)))
    return result

%timeit -n100 double_comprehension()
23.4 ms ± 67 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit -n100 list_extend()
20.5 ms ± 213 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

पायथन संस्करण: 3.8.0


0

कम करने का उपयोग कर एक समाधान :

from functools import reduce

f    = lambda x: f"f({x})" ## Just for example
g    = lambda x: f"g({x})"
data = [1, 2, 3]

reduce(lambda acc, x: acc + [f(x), g(x)], data, [])
# => ['f(1)', 'g(1)', 'f(2)', 'g(2)', 'f(3)', 'g(3)']

जबकि सूची की समझ नहीं है, यह समस्या से संपर्क करने का एक कार्यात्मक तरीका है। सूची बोध अनिवार्य रूप mapसे डेटा पर आईएनजी का एक और तरीका है , लेकिन इस मामले में जहां इनपुट और आउटपुट के बीच मैपिंग एक से एक नहीं है,reduce को कैसे उत्पन्न किया जा सकता है, इसके साथ कुछ wiggle कमरे की अनुमति देता है।

सामान्य तौर पर, forफॉर्म का कोई भी कार्यान्वयन:

result = []
for n in some_data:
  result += some_operation()
  ## etc.

(यानी किसी सूची या समान डेटा संरचना पर साइड इफ़ेक्ट उत्पन्न करने के लिए लूप के लिए)

एक घोषणात्मक map/reduce/filterकार्यान्वयन में वापस लाया जा सकता है ।

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