ফাংশনাল প্রোগ্রামিং থেকে 'ফোল্ড' ফাংশনের সমতুল্য 'পাইথোনিক' কী?


115

হাস্কেলের মধ্যে নীচের মতো কিছু অর্জনের সবচেয়ে মূর্তিমান উপায় কী:

foldl (+) 0 [1,2,3,4,5]
--> 15

বা রুবি এর সমতুল্য:

[1,2,3,4,5].inject(0) {|m,x| m + x}
#> 15

স্পষ্টতই, পাইথন reduceফাংশনটি সরবরাহ করে , যা ভাঁজগুলির বাস্তবায়ন, ঠিক উপরের মতোই, তবে আমাকে বলা হয়েছিল যে প্রোগ্রামিংয়ের 'পাইথোনিক' পদ্ধতিটি lambdaশর্তাবলী এবং উচ্চতর অর্ডার ফাংশনগুলি এড়ানো , যেখানে সম্ভব সেখানে তালিকা-বোধগম্যতা পছন্দ করে। অতএব, পাইথনের কোনও তালিকা ভাঁজ করার কোনও পছন্দনীয় উপায় বা তালিকার মতো কাঠামো যা reduceকার্যকরী নয়, বা এটি reduceঅর্জনের বুদ্ধিদীপ্ত উপায়?


2
sumযথেষ্ট ভাল না?
জেবার্নার্ডো

3
নিশ্চিত না যে এটি আপনার প্রশ্নের জন্য একটি ভাল উদাহরণ কিনা। এটি সহজেই অর্জন করা যেতে পারে sum, আপনি কয়েকটি বিভিন্ন ধরণের উদাহরণ সরবরাহ করতে চাইতে পারেন।
জামিলাক

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

1
@ মিস্টারটিম: sum()আসলে এটির সাথে সীমিত কার্যকারিতা সরবরাহ করে। উদাহরণস্বরূপ sum([[a], [b, c, d], [e, f]], [])প্রত্যাবর্তন [a, b, c, d, e, f]
জোয়েল করনেট

যদিও তালিকাগুলি দিয়ে এটি করার ক্ষেত্রে এই কৌশলটি পর্যবেক্ষণ করার জন্য জিনিসগুলির একটি ভাল প্রদর্শন - +তালিকাতে সময় এবং স্মৃতি উভয় ক্ষেত্রেই রৈখিক সময়ের ক্রিয়াকলাপ, পুরো কলটিকে দ্বিখন্ডিত করে তোলে। ব্যবহার list(itertools.chain.from_iterable([a], [b,c,d],[e,f],[]])সামগ্রিক রৈখিক - এবং যদি আপনাকে শুধুমাত্র একবারই এটি পুনরুক্তি উপর, আপনি কল ড্রপ করতে পারেন listএটি মেমরি পদ ধ্রুবক করা।
lvc

উত্তর:


114

অ্যারের যোগফলের পাইথোনিক উপায়টি ব্যবহার করছে sum। অন্যান্য উদ্দেশ্যে, আপনি কখনও কখনও reduce( functoolsমডিউল থেকে ) এবং মডিউলটির কিছু সংমিশ্রণ ব্যবহার করতে পারেন operator, যেমন:

def product(xs):
    return reduce(operator.mul, xs, 1)

সচেতন থাকুন যা হাসকলের ভাষায় reduceআসলে একটি foldl। ভাঁজগুলি সম্পাদন করার জন্য কোনও বিশেষ বাক্য গঠন নেই, বিল্টিন নেই foldrএবং প্রকৃতপক্ষে reduceঅ-সহযোগী অপারেটরগুলির সাথে ব্যবহার করা খারাপ শৈলী হিসাবে বিবেচিত হয়।

উচ্চতর অর্ডার ফাংশন ব্যবহার করা যথেষ্ট পাইথোনিক; এটি পাইথনের নীতিটির ভাল ব্যবহার করে যে ফাংশন এবং ক্লাস সহ সবকিছুই একটি বস্তু object আপনারা ঠিক বলেছেন যে ল্যাম্বডাসকে কিছু পাইথনিস্ট দ্বারা চিহ্নিত করা হয়েছে, তবে বেশিরভাগ কারণ তারা জটিল হয়ে পড়লে খুব বেশি পাঠযোগ্য হয় না।


4
@ জেবার্নার্ডো: আপনি বলছেন যে বিল্টিন মডিউলে কিছু নেই অজগর নয়?
ফ্রেড ফু

4
না, এটি বলতে বোকামি হবে। তবে আমাকে একটি কারণ দিন কেন আপনি ভাবেন যে জিভিআর এটি বিল্টিনগুলি থেকে অপসারণের মুহুর্তে এত হ্রাস কার্যকে ঘৃণা করবে ?
জেবার্নার্ডো

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

13
@ জেবার্নার্ডো, সুতরাং এর অর্থ কি হাস্কেল এবং স্কিমের ভাঁজের প্রতিটি ব্যবহার সমানভাবে খারাপ? এটি প্রোগ্রামিংয়ের একেবারেই আলাদা স্টাইল, এটিকে উপেক্ষা করে আপনার কানে আঙ্গুলগুলি রেখে এবং এটি অস্পষ্ট বলে যে এটি তা তৈরি করে না। বেশিরভাগ জিনিসের মতো যা একটি ভিন্ন স্টাইলে এটি ব্যবহার করতে অনুশীলন লাগে । ধারণাটি হ'ল জিনিসগুলিকে সাধারণ বিভাগগুলিতে স্থাপন করা হয় যাতে প্রোগ্রামগুলি সম্পর্কে যুক্তি করা সহজ হয়। "ওহ আমি এটি করতে চাই, হুম, দেখতে ভাঁজের মতো" (বা একটি মানচিত্র, বা একটি উন্মুক্ত, বা একটি উদয়টি তারপরে একটি ভাঁজ)
ওয়েস

3
পাইথনের লাম্বদাতে একাধিক এক্সপ্রেশন থাকতে পারে না। আপনি চেষ্টা করেও এটিকে জটিল করতে পারবেন না। সুতরাং পাইথনিস্টগুলি যারা এগুলি পছন্দ করে না তারা সম্ভবত অভ্যস্ত নয় এবং তাই কার্যকরী প্রোগ্রামিং শৈলী পছন্দ করে না।
গোলেম

16

Haskell,

foldl (+) 0 [1,2,3,4,5]

পাইথন

reduce(lambda a,b: a+b, [1,2,3,4,5], 0)

স্পষ্টতই, এটি একটি বিন্দুর চিত্রিত করার জন্য একটি তুচ্ছ উদাহরণ। পাইথনে আপনি ঠিক করবেন sum([1,2,3,4,5])এবং হাস্কেল পিউরিস্টরা সাধারণত পছন্দ করেন sum [1,2,3,4,5]

তুচ্ছ তাত্পর্যপূর্ণ পরিস্থিতিতে যখন কোনও সুস্পষ্ট সুবিধামূলক কার্যকারিতা না থাকে, আইডিয়োমেটিক পাইথোনিক পদ্ধতির স্পষ্টভাবে লুপের জন্য লিখিতভাবে লিখতে হয় এবং পরিবর্তিত পরিবর্তনশীল অ্যাসাইনমেন্টটি ব্যবহার reduceবা একটি ব্যবহারের পরিবর্তে ব্যবহার করা হয় fold

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


12
ভাঁজগুলি কার্যকরী "পিউরিস্ট" এর চেয়ে বেশি কার্যকর। এগুলি সাধারণ উদ্দেশ্য বিমূর্ততা। পুনরাবৃত্ত সমস্যাগুলি কম্পিউটিংয়ে বিস্তৃত। ভাঁজগুলি বয়লারপ্লেট অপসারণ করার একটি উপায় এবং ভাষাগুলিতে পুনরাবৃত্ত সমাধানগুলি নিরাপদ করার উপায় দেয় যা স্থানীয়ভাবে পুনরাবৃত্তি সমর্থন করে না offer তাই খুব ব্যবহারিক জিনিস। এই অঞ্চলে জিভিআর এর কুসংস্কার দুর্ভাগ্যজনক।
ব্রুস

12

পাইথন 3-এ, reduceসরানো হয়েছে: নোট প্রকাশ করুন । তবুও আপনি ফান্টুলস মডিউলটি ব্যবহার করতে পারেন

import operator, functools
def product(xs):
    return functools.reduce(operator.mul, xs, 1)

অন্যদিকে, ডকুমেন্টেশনগুলি forপরিবর্তে-লুপের দিকে অগ্রাধিকার ব্যক্ত করে reduce, তাই:

def product(xs):
    result = 1
    for i in xs:
        result *= i
    return result

7
reduceপাইথন 3 স্ট্যান্ডার্ড লাইব্রেরি থেকে সরানো হয়নি। আপনি দেখানোর reduceসাথে সাথে functoolsমডিউলে সরানো হয়েছে ।
কাদামাটি

@ ক্লে, আমি গুডোর মুক্তির নোটগুলি থেকে বাক্যাংশটি নিয়েছি, তবে আপনি ঠিক থাকতে পারেন :)
কিআর

5

আপনি চাকা পুনরায় উদ্ভাবন করতে পারেন:

def fold(f, l, a):
    """
    f: the function to apply
    l: the list to fold
    a: the accumulator, who is also the 'zero' on the first call
    """ 
    return a if(len(l) == 0) else fold(f, l[1:], f(a, l[0]))

print "Sum:", fold(lambda x, y : x+y, [1,2,3,4,5], 0)

print "Any:", fold(lambda x, y : x or y, [False, True, False], False)

print "All:", fold(lambda x, y : x and y, [False, True, False], True)

# Prove that result can be of a different type of the list's elements
print "Count(x==True):", 
print fold(lambda x, y : x+1 if(y) else x, [False, True, True], 0)

আপনি fআপনার পুনরাবৃত্তির ক্ষেত্রে তর্কগুলি চারপাশে বদলান।
কায়েস

7
পাইথনের পুচ্ছ পুনরাবৃত্তি অভাবের কারণে এটি দীর্ঘ তালিকাগুলিতে ভেঙে যায় এবং এটি অপব্যয়যোগ্য। উপরন্তু, এই সত্যিই "ভাঁজ" ফাংশন, নিছক কিন্তু বাম ভাঁজ, অর্থাত্ foldl, যে, নয় ঠিক কি reduceইতিমধ্যে অফার (দয়া করে মনে রাখবেন এর ফাংশন স্বাক্ষর কমাতে হয় reduce(function, sequence[, initial]) -> value-, এটা খুব, একটি প্রাথমিক মান দান কার্যকারিতা অন্তর্ভুক্ত সঁচায়ক)।
cemper93

5

সত্যই প্রশ্নের উত্তর নয়, তবে ভাঁজ এবং ফোল্ডারের জন্য এক-লাইনার:

a = [8,3,4]

## Foldl
reduce(lambda x,y: x**y, a)
#68719476736

## Foldr
reduce(lambda x,y: y**x, a[::-1])
#14134776518227074636666380005943348126619871175004951664972849610340958208L

2
আমি মনে করি এটা আপনার foldr লিখতে একটি ভাল উপায় হল: reduce(lambda y, x: x**y, reversed(a))। এটির এখন আরও প্রাকৃতিক ব্যবহার রয়েছে, পুনরাবৃত্তকারীদের সাথে কাজ করে এবং কম স্মৃতি গ্রহণ করে।
মতিন উলহাক

5

শুরু Python 3.8, এবং অ্যাসাইনমেন্ট এক্সপ্রেশন (PEP 572) ( :=অপারেটর) এর পরিচিতি , যা কোনও এক্সপ্রেশনের ফলাফলের নামকরণের সম্ভাবনা দেয়, আমরা অন্য ভাষাগুলি কী ভাঁজ / ভাঁজ / কল্পনা অপারেশন হ্রাস করে তা প্রতিলিপি করতে একটি তালিকা উপলব্ধি ব্যবহার করতে পারি:

একটি তালিকা দেওয়া হয়েছে, একটি হ্রাসকরণ ফাংশন এবং একটি সঞ্চালক:

items = [1, 2, 3, 4, 5]
f = lambda acc, x: acc * x
accumulator = 1

আমরা ভাঁজ করতে itemsসঙ্গে fঅর্ডার ফল প্রাপ্ত accumulation:

[accumulator := f(accumulator, x) for x in items]
# accumulator = 120

বা একটি ঘনীভূত গঠিত:

acc = 1; [acc := acc * x for x in [1, 2, 3, 4, 5]]
# acc = 120

মনে রাখবেন যে তালিকার বোধগম্যের ফলাফল হিসাবে এটি আসলে একটি "স্ক্যানলেফ্ট" অপারেশনও প্রতিটি পদক্ষেপে জমে থাকা অবস্থার প্রতিনিধিত্ব করে:

acc = 1
scanned = [acc := acc * x for x in [1, 2, 3, 4, 5]]
# scanned = [1, 2, 6, 24, 120]
# acc = 120

3

সমস্যার (আসল) সমস্যার প্রকৃত উত্তর হ'ল কেবল একটি লুপ ব্যবহার করুন!

initial_value = 0
for x in the_list:
    initial_value += x #or any function.

এটি হ্রাস করার চেয়ে দ্রুত হবে এবং পাইপাইয়ের মতো জিনিসগুলি এর মতো লুপগুলি অনুকূল করতে পারে।

বিটিডাব্লু, যোগফলটি sumফাংশন দিয়ে সমাধান করা উচিত


4
এটি উদাহরণস্বরূপ উদাহরণ হিসাবে এটি পাইথোনিক হিসাবে বিবেচিত হবে না।
জামিলাক

7
পাইথন লুপগুলি কুখ্যাতভাবে ধীর। reduceপাইথন প্রোগ্রামটি অনুকূলকরণের (বা আপত্তিজনক) ব্যবহার একটি সাধারণ উপায়।
ফ্রেড ফু

1
@larmans দয়া করে, বলুন না যে হ্রাস হ্রাস একটি সাধারণ লুপের চেয়ে দ্রুত ... এটি প্রতিটি পুনরাবৃত্তির জন্য সর্বদা একটি ফাংশন কল ওভারহেড থাকবে। এছাড়াও, আবারও পাইপি সি গতিতে লুপগুলি অনুকূল করতে পারে
জেবার্নার্ডো

1
@ জেবার্নার্ডো: হ্যাঁ, আমি এটাই দাবি করছি। আমি কেবল productআপনার শৈলীতে একটির বিপরীতে আমার সংস্করণটি পোস্ট করেছি এবং এটি দ্রুত (প্রান্তিক হলেও)।
ফ্রেড ফু

1
@ জবার্নার্ডো operator.addহ্রাস করার যুক্তি হিসাবে একটি বিল্টিন ফাংশন (যেমন ) ধরে নিচ্ছেন : এই অতিরিক্ত কলটি একটি সি কল (যা পাইথন কলের তুলনায় অনেক সস্তা) এবং এটি কয়েকটা বাইটকোড নির্দেশাবলী প্রেরণ ও ব্যাখ্যা সংরক্ষণ করে, যা কয়েক ডজন সহজেই সৃষ্টি করতে পারে ফাংশন কল।

1

আমি বিশ্বাস করি যে এই প্রশ্নের উত্তরকারীদের মধ্যে কিছু foldবিমূর্ত সরঞ্জাম হিসাবে ফাংশনটির বিস্তৃত অর্থে মিস করেছেন । হ্যাঁ, sumপূর্ণসংখ্যার তালিকার জন্য একই জিনিসটি করতে পারেন তবে এটি একটি তুচ্ছ ঘটনা। foldআরও জেনেরিক। আপনি যখন বিভিন্ন আকারের ডেটা স্ট্রাকচারের ক্রম রাখেন এবং পরিষ্কারভাবে একটি সমষ্টি প্রকাশ করতে চান এটি কার্যকর is সুতরাং forএকটি সামগ্রিক ভেরিয়েবলের সাথে একটি লুপ তৈরির পরিবর্তে এবং প্রত্যেকবার ম্যানুয়ালি এটি পুনরায় সংশোধন করার পরিবর্তে একটি foldফাংশন (বা পাইথন সংস্করণ, যা reduceঅনুরূপ বলে মনে হয়) প্রোগ্রামারকে কেবল আরও সহজলভ্যভাবে সরবরাহের মাধ্যমে সমষ্টিটির অভিপ্রায় প্রকাশ করতে দেয় দুটি জিনিস:

  • সমষ্টি জন্য একটি ডিফল্ট শুরু বা "বীজ" মান।
  • একটি ফাংশন যা তালিকার সামঞ্জস্যের বর্তমান মান ("বীজ" দিয়ে শুরু করে) এবং পরবর্তী উপাদানটি গ্রহণ করে এবং পরবর্তী সম্মিলনের মান প্রদান করে।

হাই আরকিউ_! আমি মনে করি আপনার উত্তরটি উন্নত হবে এবং আপনি যদি foldপাইথনের পরিষ্কার-পরিচ্ছন্নভাবে কাজ করা কঠিন এবং এরপরে foldপাইথনে " ": "
স্কট স্কাইলস

0

আমি পার্টিতে বেশ দেরি করতে পারি, তবে আমরা foldrসাধারণ ল্যাম্বদা ক্যালকুলাস এবং তরকারী ফাংশন ব্যবহার করে কাস্টম তৈরি করতে পারি । পাইথনে আমার ফোল্ডারের প্রয়োগ এখানে।

def foldr(func):
    def accumulator(acc):
        def listFunc(l):
            if l:
                x = l[0]
                xs = l[1:]
                return func(x)(foldr(func)(acc)(xs))
            else:
                return acc
        return listFunc
    return accumulator  


def curried_add(x):
    def inner(y):
        return x + y
    return inner

def curried_mult(x):
    def inner(y):
        return x * y
    return inner

print foldr(curried_add)(0)(range(1, 6))
print foldr(curried_mult)(1)(range(1, 6))

যদিও বাস্তবায়নটি পুনরাবৃত্ত হয় (এটি ধীর হতে পারে) তবে এটি যথাক্রমে মানগুলি 15এবং মুদ্রণ করবে120

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