Erlang

2012-02-18 15 views
5

में नेस्टेड सूचियों की एक सूची फ़्लैट करें मैं एरलांग प्रोग्रामिंग में अभ्यास पर काम कर रहा हूं।Erlang

सवाल

एक समारोह है कि, नेस्टेड सूचियों की एक सूची दी गई, एक फ्लैट सूची प्रदान करेगा लिखें है।

उदाहरण: flatten([[1,[2,[3],[]]], [[[4]]], [5,6]]) ⇒ [1,2,3,4,5,6].

सुझाव: concatenate का उपयोग flatten हल करने के लिए।

और यहाँ मेरी concatenate समारोह

%% concatenate([[1,2,3], [], [4, five]]) ⇒ [1,2,3,4,five]. 
concatenate([X|Xs]) -> concat(X, Xs, []). 
concat([X|Xs], T, L) -> concat(Xs, T, [X|L]); 
concat([], [X|Xs], L) -> concat(X, Xs, L); 
concat([], [], L) -> reverse(L). 

मैं वास्तव में flatten लागू करने के लिए एक सुंदर तरीका जानना चाहते है। मैंने इस अभ्यास को हल करने में घंटों बिताए हैं।

अद्यतन: मैं सबसे महत्वपूर्ण शर्त भूल जाता हूं। क्या इस समस्या को केवल रिकर्सन और पैटर्न मिलान से हल करना संभव है?

+0

हाँ, यह संभव है! – rvirding

उत्तर

14

मैं इस तरह से

flatten(X) -> lists:reverse(flatten(X,[])). 

flatten([],Acc) -> Acc; 
flatten([H|T],Acc) when is_list(H) -> flatten(T, flatten(H,Acc)); 
flatten([H|T],Acc) -> flatten(T,[H|Acc]). 

परीक्षण की कोशिश करेगा

my:flatten([[1,[2,[3],[]]], [[[4]]], [5,6]]). 
[1,2,3,4,5,6] 

युपीडी: या इस तरह से, गार्ड के बिना और रिवर्स, केवल पुनरावर्ती कॉल और पैटर्न मिलान।

flatten(X)    -> flatten(X,[]). 

flatten([],Acc)   -> Acc; 
flatten([[]|T],Acc)  -> flatten(T, Acc); 
flatten([[_|_]=H|T],Acc) -> flatten(T, flatten(H,Acc)); 
flatten([H|T],Acc)  -> flatten(T,Acc++[H]) . 
+0

क्या यह समस्या केवल रिकर्सन और पैटर्न मिलान के साथ हल करना संभव है? – Vayn

+0

संकेत ने मुझे पूरी तरह से गुमराह किया। धन्यवाद! – Vayn

+2

'++' का उपयोग अक्षम है क्योंकि यह पूरी सूची की प्रतिलिपि बनाता है। – rvirding

0

प्रश्न की कुंजी "विभाजित और जीत" है।

प्रोग्रामिंग समय बचाने के लिए एक और अतिरिक्त फ़ंक्शन "सूचियां: रिवर्स" और ऑपरेटर "++" का उपयोग किया जाता है। परीक्षण:

my_flat([],Result)-> lists:reverse(Result); my_flat([H|T],Result) when is_atom(H) -> case T of []-> my_flat([],[H|Result]); _Else -> my_flat(T,[H|Result]) end; my_flat([H|T],Result) when is_number(H)-> case T of []-> my_flat([],[H|Result]); _Else -> my_flat(T,[H|Result]) end; my_flat([H|T],Result) -> my_flat(H,Result)++my_flat(T,[]).
अपने परीक्षण के लिए

my_flat ([[1, [2, [3], []]], [[[4]]], [5,6]], []) ।

5

कुछ अलग समाधान, हो रही चालाक और होशियार:

%% Lift nested lists to the front of the list. 
flatten1([[H|T1]|T2]) -> flatten1([H,T1|T2]); 
flatten1([[]|T]) -> flatten1(T); 
flatten1([E|T]) -> [E|flatten1(T)]; 
flatten1([]) -> []. 

या

%% Keep a list of things todo and put tails onto it. 
flatten2(L) -> flatten2(L, []). 

flatten2([H|T], Todo) -> 
    flatten2(H, [T|Todo]); 
flatten2([], [H|Todo]) -> flatten2(H, Todo); 
flatten2([], []) -> []; 
flatten2(E, Todo) -> [E|flatten2(Todo, [])]. 

या

%% Work from the back and keep a tail of things done. 
flatten3(L) -> flatten3(L, []). 

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

ये केवल पैटर्न मिलान और प्रत्यावर्तन के साथ सभी कर रहे हैं, लेकिन वे वाई में सुधार किया जा सकता है कुछ गार्ड प्रकार परीक्षण। ++ का उपयोग अक्षम है क्योंकि यह हर बार सूची की प्रतिलिपि बनाता है। lists मॉड्यूल अंतिम खंड के बजाए गार्ड प्रकार परीक्षण के साथ अंतिम के संस्करण का उपयोग करता है।

+0

है मैंने पाया [यह] (http://stackoverflow.com/a/1131941/419206)। तो मुझे ++ ऑपरेटर का उपयोग कब करना चाहिए? – Vayn

+0

और अब मुझे लगता है कि Quicksort को लागू करने के लिए उपयोग सूची समझ और ++ ऑपरेटर एक अच्छा विचार नहीं है :( – Vayn

+2

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

2

सुंदर संक्षिप्त और सरल संस्करण:

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

flatten([[_|_]=H|T]) -> append(flatten(H), flatten(T)); 
flatten([[]|T]) -> flatten(T); 
flatten([H|T]) -> [H|flatten(T)]; 
flatten([]) -> []. 
+0

धन्यवाद। मैं लगभग था यह समाधान देखने के बाद खुद को इस समाधान की आपूर्ति करें कि अन्य समाधान खराब तरीके से ++ का उपयोग करते हैं। –

+0

@DanielLuna, संलग्न ++ –

+0

@ ओडोबेनस रोस्मरस के बराबर है: न तो '++' और न ही 'संलग्न' समस्या है लेकिन ** खराब तरीके से उपयोग करें * * है। मैं 'एपेंड' लगा रहा हूं जिसमें चपटे सिर के ट्रैवर्सल के साथ आप इसका उपयोग कर रहे हैं 'एसी' बढ़ाना जो कि बहुत गलत है। मुझे लगता है कि व्यायाम के लिए भी गलत है। –

2

CONCATENATE/1 के रूप में किताब में परिभाषित एक समतल समारोह जो केवल एक ही स्तर नीचे सपाट रूप में काम करता है। ([[1],[2]][1,2] बन जाता है, [[[1]],[[2]]][[1],[2]], आदि बन जाता है) संकेत में सुझाई गई रणनीति फ़्लैटन/1 में नए तर्क को परिभाषित करके पूरी तरह से फ़्लैट करना नहीं है बल्कि फ्लैटन/1 की रिकर्सिव कॉल में कॉन्सटेनेट/1 का उपयोग करके।

concatenate(Ls) -> 
    reverse(concatenate(Ls, [])). 

concatenate([], Acc) -> 
    Acc; 
concatenate([[]|Rest], Acc) -> 
    concatenate(Rest, Acc); 
concatenate([[H|T]|Rest], Acc) -> 
    concatenate([T|Rest], [H|Acc]); 
concatenate([H|T], Acc) -> 
    concatenate(T, [H|Acc]). 

flatten(L) -> 
    flatten(L, []). 

flatten([], Acc) -> 
    Acc; 
flatten(L, Acc) -> 
    Concatted = concatenate(L), 
    [Non_lists|Remainder] = find_sublist(Concatted), 
    flatten(Remainder, concatenate([Acc, Non_lists])). 

find_sublist(L) -> 
    find_sublist(L, []). 

find_sublist([], Acc) -> 
    reverse(Acc); 
find_sublist(L = [[_|_]|_], Acc) -> 
    [reverse(Acc)|L]; 
find_sublist([H|T], Acc) -> 
    find_sublist(T, [H|Acc]). 

tests() -> 
    [1,2,3,4,4,5,6,7,8] = flatten([[1,[2,[3],[]]], [[[4,[4]]]], [[5],6], [[[]]], [], [[]], [[[7, 8]]]]), 
    [1,2] = flatten([[1,2]]), 
    [1,2,3] = flatten([[1],[2],[3]]), 
    [1,2,3,4,5,6] = flatten([[1,[2,[3],[]]], [[[4]]], [5,6]]), 
    tests_successful.