Erlang 21 - 5. List Handling

5 सूची हैंडलिंग




erlang

5 सूची हैंडलिंग

5.1 एक सूची बनाना

सूचियाँ केवल अंत से शुरू करके बनाई जा सकती हैं और शुरुआत में सूची तत्वों को संलग्न कर सकती हैं। यदि आप निम्नानुसार " ++ " ऑपरेटर का उपयोग करते हैं, तो एक नई सूची बनाई जाती है जो सूची 1 में तत्वों की एक प्रति है, इसके बाद List2 :

List1 ++ List2

कैसे lists:append/1 को देखते हुए lists:append/1 या ++ सादे इलंग में लागू किया जाएगा, स्पष्ट रूप से पहली सूची की प्रतिलिपि बनाई गई है:

append([H|T], Tail) ->
    [H|append(T, Tail)];
append([], Tail) ->
    Tail.

जब किसी सूची का पुनर्पाठ और निर्माण किया जाता है, तो यह सुनिश्चित करना महत्वपूर्ण है कि आप सूची की शुरुआत में नए तत्वों को संलग्न करें। इस तरह, आप एक सूची का निर्माण करेंगे, बढ़ती परिणाम सूची की सैकड़ों या हजारों प्रतियां नहीं।

आइए पहले देखें कि यह कैसे किया जाना है:

ऐसा न करें

bad_fib(N) ->
    bad_fib(N, 0, 1, []).

bad_fib(0, _Current, _Next, Fibs) ->
    Fibs;
bad_fib(N, Current, Next, Fibs) -> 
    bad_fib(N - 1, Next, Current + Next, Fibs ++ [Current]).

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

प्रत्येक पुनरावृत्ति में परिणाम की प्रतिलिपि बनाने से बचने के लिए, सूची को रिवर्स ऑर्डर में बनाएं और जब आप कर रहे हों तो सूची को उल्टा कर दें:

करना

tail_recursive_fib(N) ->
    tail_recursive_fib(N, 0, 1, []).

tail_recursive_fib(0, _Current, _Next, Fibs) ->
    lists:reverse(Fibs);
tail_recursive_fib(N, Current, Next, Fibs) -> 
    tail_recursive_fib(N - 1, Next, Current + Next, [Current|Fibs]).

5.2 सूची बोध

सूचियों की समझ अभी भी धीमी होने के लिए एक प्रतिष्ठा है। उन्हें फन का उपयोग करके कार्यान्वित किया जाता था, जो धीमा हुआ करता था।

एक सूची समझ:

[Expr(E) || E <- List]

मूल रूप से एक स्थानीय समारोह में अनुवादित है:

'lc^0'([E|Tail], Expr) ->
    [Expr(E)|'lc^0'(Tail, Expr)];
'lc^0'([], _Expr) -> [].

यदि सूची की समझ का परिणाम स्पष्ट रूप से उपयोग नहीं किया जाएगा, तो एक सूची का निर्माण नहीं किया जाएगा। उदाहरण के लिए, इस कोड में:

[io:put_chars(E) || E <- List],
ok.

या इस कोड में:

...
case Var of
    ... ->
        [io:put_chars(E) || E <- List];
    ... ->
end,
some_function(...),
...

मान एक चर को नहीं सौंपा गया है, दूसरे फ़ंक्शन को पारित नहीं किया गया है, और वापस नहीं किया गया है। इसका मतलब है कि सूची बनाने की कोई आवश्यकता नहीं है और संकलक सूची की समझ के लिए कोड को सरल करेगा:

'lc^0'([E|Tail], Expr) ->
    Expr(E),
    'lc^0'(Tail, Expr);
'lc^0'([], _Expr) -> [].

संकलक भी समझता है कि '_' को निर्दिष्ट करने का अर्थ है कि मूल्य का उपयोग नहीं किया जाएगा। इसलिए, निम्न उदाहरण में कोड भी अनुकूलित किया जाएगा:

_ = [io:put_chars(E) || E <- List],
ok.

5.3 गहरी और सपाट सूची

lists:flatten/1 पूरी तरह से एक नई सूची बनाता है। यह इसलिए महंगा है, और ++ ऑपरेटर की तुलना में अधिक महंगा है (जो इसके बाएं तर्क की प्रतिलिपि बनाता है, लेकिन इसका सही तर्क नहीं)।

निम्नलिखित स्थितियों में, आप आसानी से कॉलिंग lists:flatten/1 से बच सकते हैं lists:flatten/1 :

  • पोर्ट पर डेटा भेजते समय। पोर्ट गहरी सूचियों को समझते हैं इसलिए पोर्ट पर भेजने से पहले सूची को समतल करने का कोई कारण नहीं है।
  • BIF को कॉल करते समय जो गहरी सूचियों को स्वीकार करते हैं, जैसे list_to_binary/1 या iolist_to_binary/1
  • जब आप जानते हैं कि आपकी सूची केवल एक स्तर गहरी है, तो आप lists:append/1 उपयोग कर सकते हैं lists:append/1

पोर्ट उदाहरण

करना

...
port_command(Port, DeepList)
...

ऐसा न करें

...
port_command(Port, lists:flatten(DeepList))
...

पोर्ट पर शून्य-टर्मिनेटेड स्ट्रिंग भेजने का एक सामान्य तरीका निम्नलिखित है:

ऐसा न करें

...
TerminatedStr = String ++ [0], % String="foo" => [$f, $o, $o, 0]
port_command(Port, TerminatedStr)
...

बजाय:

करना

...
TerminatedStr = [String, 0], % String="foo" => [[$f, $o, $o], 0]
port_command(Port, TerminatedStr) 
...

उदाहरण प्रस्तुत करें

करना

> lists:append([[1], [2], [3]]).
[1,2,3]
>

ऐसा न करें

> lists:flatten([[1], [2], [3]]).
[1,2,3]
>

5.4 पुनरावर्ती सूची कार्य

मिथकों के बारे में अनुभाग में, निम्नलिखित मिथक को उजागर किया गया था: Tail-Recursive Functions are Much Faster Than Recursive Functions

शरीर-पुनरावर्ती सूची फ़ंक्शन और पूंछ-पुनरावर्ती फ़ंक्शन के बीच आमतौर पर बहुत अंतर नहीं होता है जो सूची को अंत में उलट देता है। इसलिए, सुंदर कोड लिखने पर ध्यान केंद्रित करें और अपनी सूची के कार्यों के प्रदर्शन के बारे में भूल जाएं। आपके कोड (और केवल वहाँ) के समय-महत्वपूर्ण भागों में, अपने कोड को फिर से लिखने से पहले मापें

ध्यान दें

यह खंड उन सूची कार्यों के बारे में है जो सूचियों का निर्माण करते हैं। एक पूंछ-पुनरावर्ती फ़ंक्शन जो सूची का निर्माण नहीं करता है वह निरंतर स्थान में चलता है, जबकि संबंधित शरीर-पुनरावर्ती फ़ंक्शन सूची की लंबाई के लिए आनुपातिक स्थान का उपयोग करता है।

उदाहरण के लिए, एक फ़ंक्शन जो पूर्णांक की एक सूची को प्रस्तुत करता है, उसे इस प्रकार नहीं लिखा जाना चाहिए:

ऐसा न करें

recursive_sum([H|T]) -> H+recursive_sum(T);
recursive_sum([])    -> 0.

बजाय:

करना

sum(L) -> sum(L, 0).

sum([H|T], Sum) -> sum(T, Sum + H);
sum([], Sum)    -> Sum.