2011-10-26 46 views
1

我正在尋找執行此凌亂程序邏輯的功能的方法:使用不同的分隔符連接數組值的功能方法?

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 

我基本上有對象(所有相同類型)的陣列,並且需要加入他們#name屬性,但以下內容的對象,該對象有一個特殊的特點,我需要一個不同的分隔符。

這是一個容易解決的問題,但我正在尋找最乾淨,功能最強大的方法。我第一次潛入#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 

替代措辭(紅寶石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小提琴:) – d11wtq

+0

@ d11wtq:請注意each_cons(2)= pairwise。看看重構,我認爲你不需要一個帶有內存的算法。 – tokland

+0

'each_cons'和'flat_map'似乎返回不與'join'或'slice'一起工作的枚舉器,並且在它們上調用'to_a'似乎只是給它一個帶有Enumerator的Array,使得我的String成爲一個巨大的枚舉器#to_s輸出。我會繼續擺弄......我認爲這絕對是我正在考慮的方向:) – d11wtq

1

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

編輯,解決方案採用注入:

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呵呵,這是真的。我以前有過,但是希望避免尾隨分隔符,因爲後處理將其刪除並不容易(因爲它們看起來是相同的,所以它不明確是一個值還是分隔符)。 – 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
values.inject('') { |m, e| m << e.to_s; m << (e.special? ? '/x/' : '/' } 

爲了使其功能完全可以每次重新創建m而不是附加到它。

,避免最後一次迭代,或許更復雜的東西,如:

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

是否需要分號?順便說一句,我遇到的問題是決定如何去掉尾隨分隔符,因爲如果'/ x /'實際上是值'x'後跟'/',或者分隔符'/ x/'。 – d11wtq

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破壞了他原來的陣列。