2011-10-26 5 views
1

私はこの厄介な手続きロジック実行するための機能的な方法を探しています:私は基本的にオブジェクトの配列(すべて同じタイプ)を持っており、彼らの#name属性に参​​加する必要がありますが、そのオブジェクトには、次の値の配列を変化するセパレータと結合する機能的アプローチ?

values = [a, b, c, d, e, f] 
last_value = nil 
string = "" 
values.each do |v| 
    string << if last_value && last_value.special? 
    "/x/" + v.name.to_s 
    else 
    "/" + v.name.to_s 
    end 
    last_value = v 
end 

を私は別のセパレーターが必要です。

これは簡単に解決される問題ですが、最もクリーンで機能的なアプローチを探しています。最初は#injectに分割されましたが、各繰り返しで以前の値が失われてしまいました。何か案は?

あなたはおそらくとにかくそれを実行することができませんでしたので、申し訳ありませんが、私は実際のコードの代わりに、擬似コードを投稿してみたいが、それはDataMapperの関係のものは本当に緻密で複雑だ:(

+0

実際には、最後に先行するスラッシュを削除する必要があるので、私が投稿するコードには欠陥があります。値の間に結合されているだけではありません。 – d11wtq

+0

「特別な」部分について詳しく説明できますか?/x /は、特別なものの前に、特別なものの後に、あるいは値の間に特別なものがある必要がありますか? –

+0

/x /は特別な*の後に*する必要がありますが、出力文字列の最後で終わるべきではありません。中間にのみ表示するべきです( 'Array#join'のように)。 – d11wtq

答えて

1

私はあなたが望むものを正確に理解していれば、これは動作するはずです:

output = values.map do |v| 
    ["/" + v.name.to_s, v.special? ? "/x" : ""] 
end.flatten[0...-1].join 

代替フレージング(Ruby 1.9の):

output = "/" + values.flat_map do |v| 
    [v.name.to_s, ("x" if v.special?)] 
end.take(2*values.size - 1).join("/") 

アルゴリズムを解析することなく、ただそれを作ります機能:

output = ([nil] + values).each_cons(2).map do |last_value, v| 
    if last_value && last_value.special? 
    "/x/" + v.name.to_s 
    else 
    "/" + v.name.to_s 
    end 
end.join 
+0

うわー、 '#each_cons'に私を紹介してくれてありがとう、それはすてきです!これは完璧かもしれません。 Lemme fiddle :) – d11wtq

+0

@ d11wtq:each_cons(2)= pairwiseに注意してください。リファクタを見て、私はあなたがメモリとアルゴリズムを必要としないと思う。 – tokland

+0

'each_cons'と' flat_map'は 'join'または' slice'では動作しません列挙子を返すように見える、そしてそれらの上に呼び出す 'to_a'は私の文字列aを作り、ちょうど私にその中列挙子を持つ配列を与えているようです巨大な列挙子#to_s出力。更新され、最初のバージョンは1.8で正常に動作する必要があります:私は、私はこれは私がd11wtq @ :) – d11wtq

1

values.collect{|v| v.special? ? v + "/x/" : v + "/"}.join("")

を試してみてください

EDIT、ソリューション注入使用:

values.inject(["", ""]) {|path_and_sep, item| [path_and_sep[0] + path_and_sep[1] + item, item.special? "/x/" : "/"]} [0]

+0

これは現在の値に基づいて切り替わります。私は、前の値に基づいて切り替える必要があります。これは、合併症が存在する場所です。 – d11wtq

+0

区切り記号を前にではなく、現在の値の後に挿入します。私は私の答えを更新しました。 – socha23

+0

+1 Hehe、これは本当です。それは(それは彼らが同じように見えるので、それは、値、またはセパレータのかどうか曖昧だとして)それを削除するには、ポストプロセスに簡単ではありませんので、私は、この前に持っていたが、末尾の区切りを避けたかったです。 – d11wtq

1

エンド大手を取り除くと/を末尾に取得することで参加してください:

values.collect{|v| v.special? && v != values.last ? [v.name.to_s, "x"] : v.name.to_s}.flatten.join("/") 
+0

'values.last'は、繰り返しの前の値ではなく、配列の終わりを返します。 – d11wtq

+0

ああ、また、私は前の値に基づいて、現在のものに基づいて切り替える必要があります。私も自分自身を混乱させ始めています:P – d11wtq

+0

はい、私は値とセパレータを反転したので、最後の値と比較しています。元の例では、最後の値の後にセパレータは挿入されません**。 –

0
values.map{|x| x.special? ? [x, SEPARATOR_2] : [x, SEPARATOR_1]}.flatten[0..-2].join('') 
0

完全に機能させるには、追加する代わりにmを毎回作り直すことができます。

そしておそらく、のような、より複雑な何か最後の繰り返しを避けるために:

delay = '' 
values.inject('') do |m, e| 
    m << delay << e.to_s 
    delay = e.special? ? '/x/' : '/' 
    m 
end 
+0

はセミコロンが必要とされている);私はまだそれはそれがなかった状態で終わったかどうかはわかりませんが、それはダウン私はp' 'で結果を印刷しようとしましたか?ところで、私がこれで抱えている問題は、 '/ x /'が実際に値 'x'の後に'/'があるか、セパレータ'/x/'が'/'で区切られていて、 '。 – d11wtq

1

を、私は1つの特に誇りに思ってないんだけど、それは一種の機能です;)

values.clone.unshift(nil).each_cons(2).map { |last_value, v| 
    last_value.special? ? "/x/" + v.to_s : "/" + v.to_s 
}.join() 

クローンeach_consが元の配列を破壊するために必要です。

関連する問題