2016-12-29 5 views
7

मेरे पास दो कॉलम, टेक्स्ट और गिनती के साथ एक CSV फ़ाइल है। लक्ष्य इस से फ़ाइल को बदलने के लिए है:एफ # में, मैं एक बड़ी पाइपलाइन के संदर्भ में Seq.unfold का उपयोग कैसे करूं?

some text once,1 
some text twice,2 
some text thrice,3 
इस के लिए

:

some text once,1 
some text twice,1 
some text twice,1 
some text thrice,1 
some text thrice,1 
some text thrice,1 

प्रत्येक पंक्ति गिनती बार दोहरा और है कि कई लाइनों पर गिनती फैल गया।

यह Seq.unfold लिए एक अच्छे उम्मीदवार की तरह मुझे लगता है,, अतिरिक्त लाइनें पैदा करने के रूप में हम फ़ाइल को पढ़ने। मैं निम्नलिखित जनरेटर समारोह है:

let expandRows (text:string, number:int32) = 
    if number = 0 
    then None 
    else 
     let element = text     // "element" will be in the generated sequence 
     let nextState = (element, number-1) // threaded state replacing looping 
     Some (element, nextState) 

FSI पैदावार एक निम्नलिखित समारोह हस्ताक्षर:

val expandRows : text:string * number:int32 -> (string * (string * int32)) option 

FSI में निम्नलिखित को निष्पादित:

let expandedRows = Seq.unfold expandRows ("some text thrice", 3) 

पैदावार की उम्मीद:

val it : seq<string> = seq ["some text thrice"; "some text thrice"; "some text thrice"] 

सवाल यह है: मैं इसे एक बड़ी ईटीएल पाइपलाइन के संदर्भ में कैसे प्लग करूं? उदाहरण के लिए:

File.ReadLines(inFile)     
    |> Seq.map createTupleWithCount 
    |> Seq.unfold expandRows // type mismatch here 
    |> Seq.iter outFile.WriteLine 

पाइपलाइन के संदर्भ में नीचे दी गई त्रुटि विस्तार पर है।

Type mismatch. 
Expecting a 'seq<string * int32> -> ('a * seq<string * int32>) option'  
but given a  'string * int32 -> (string * (string * int32)) option' 
The type 'seq<string * int 32>' does not match the type 'string * int32' 

मुझे उम्मीद थी कि विस्तार अलग-अलग परीक्षण में, स्ट्रिंग की सीईसी वापस कर रहा था। जैसा कि न तो "उम्मीद" या "दिया गया" है, मैं उलझन में हूं। क्या कोई मुझे सही दिशा दिखा सकता है?

कोड के लिए एक सार यहाँ है: https://gist.github.com/akucheck/e0ff316e516063e6db224ab116501498

उत्तर

6

Seq.map अनुक्रम उत्पन्न करता है, लेकिन Seq.unfold अनुक्रम नहीं लेता है, यह एक एकल मूल्य लेता है। तो आप सीधे Seq.map के आउटपुट को Seq.unfold में पाइप नहीं कर सकते हैं। इसके बजाय आपको तत्व द्वारा तत्व को करने की आवश्यकता है।

लेकिन फिर, प्रत्येक तत्व अपने Seq.unfold एक दृश्य का उत्पादन करेगा, तो अंतिम परिणाम के लिए दृश्यों के एक दृश्य हो जाएगा। आप Seq.collect के साथ उन सभी "subsequences" एक ही क्रम में इकट्ठा कर सकते हैं:

File.ReadLines(inFile) 
    |> Seq.map createTupleWithCount 
    |> Seq.collect (Seq.unfold expandRows) 
    |> Seq.iter outFile.WriteLine 

Seq.collect एक समारोह और एक इनपुट अनुक्रम लेता है।इनपुट अनुक्रम के प्रत्येक तत्व के लिए, फ़ंक्शन को एक और अनुक्रम उत्पन्न करना चाहिए, और Seq.collect उन सभी अनुक्रमों को एक साथ जोड़ देगा। आप Seq.collect को Seq.map और Seq.concat के रूप में एक फ़ंक्शन में जोड़ सकते हैं। इसके अलावा, यदि आप सी # से आ रहे हैं, Seq.collect को वहां पर SelectMany कहा जाता है।

+0

बहुत उपयोगी स्पष्टीकरण; बिल्कुल मुझे क्या चाहिए। धन्यवाद! – akucheck

+0

खुशी है कि मैं मदद कर सकता हूं। –

2

कि आप क्या करना चाहते हैं की तरह लगता है वास्तव में

File.ReadLines(inFile)     
|> Seq.map createTupleWithCount 
|> Seq.map (Seq.unfold expandRows) // Map each tuple to a seq<string> 
|> Seq.concat // Flatten the seq<seq<string>> to seq<string> 
|> Seq.iter outFile.WriteLine 

ऐसा लगता है कि आप में अपने अनुक्रम में गिनती के साथ प्रत्येक टपल परिवर्तित करना चाहते है seq<string>Seq.unfold और expandRows के माध्यम से। यह मैपिंग द्वारा किया जाता है।

बाद में, आप अपने seq<seq<string>> को बड़े seq<string> में फ़्लैट करना चाहते हैं, जो Seq.concat के माध्यम से नीचे है।

+3

'मानचित्र >> concat' ===' संग्रह ' –

+0

डोप। मैं इकट्ठा करने के बारे में भूल गया। याद दिलाने के लिए शुक्रिया! – Ringil

6

इस मामले में, चूंकि आप बस कई बार मूल्य दोहराना चाहते हैं, Seq.unfold का उपयोग करने का कोई कारण नहीं है। आप Seq.replicate बजाय का उपयोग कर सकते हैं:

// 'a * int -> seq<'a> 
let expandRows (text, number) = Seq.replicate number text 

आप Seq.collect उपयोग कर सकते हैं यह रचना के लिए:

File.ReadLines(inFile) 
|> Seq.map createTupleWithCount 
|> Seq.collect expandRows 
|> Seq.iter outFile.WriteLine 

वास्तव में, केवल काम expandRows के इस संस्करण द्वारा किया जाता एक टपल 'खोल' करने के लिए है और अपने मूल्यों को करीबी रूप में लिखें।

एफ # अपने मूल पुस्तकालय में इस तरह के एक सामान्य समारोह के साथ नहीं आता है, आप आसानी से इसे (और other similarly useful functions) को परिभाषित कर सकते हैं:

module Tuple2 = 
    let curry f x y = f (x, y)  
    let uncurry f (x, y) = f x y  
    let swap (x, y) = (y, x) 

यह आपके पाइपलाइन रचना करने के लिए सक्षम हैं प्रसिद्ध से कार्यात्मक बिल्डिंग ब्लॉक:

File.ReadLines(inFile) 
|> Seq.map createTupleWithCount 
|> Seq.collect (Tuple2.swap >> Tuple2.uncurry Seq.replicate) 
|> Seq.iter outFile.WriteLine 
+0

मुझे Seq.unfold को हटाकर सरलीकृत करने के विचार से प्यार है, लेकिन मुझे एमएसडीएन दस्तावेज़ में Seq.replicate का कोई संदर्भ नहीं दिखता है। मैं क्या देख रहा हूँ – akucheck

+0

दिलचस्प। एफएसआई में काम करता है, संकलित करता है, मोनो डब्ल्यू सिस्टम पर रनटाइम पर विफल रहता है। MissingMethodException। इस में खोदने की जरूरत है ... – akucheck

+1

@akucheck 'Seq.replicate' को F # 4 में जोड़ा गया था: https://github.com/Microsoft/visualfsharp/blob/fsharp4/CHANGELOG.md –

संबंधित मुद्दे