iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 12
0
Modern Web

Ruby礦工的Rails地圖系列 第 12

How to mix around Unlimited Array

每天最痛苦的就是想文章梗
不能超乎自己的能力範圍,也不能過於簡單
剛剛看到疑似是站方人員將系列文的其中一篇貼在新手村
還表示這系列是閱覽量的前十名,瞬間覺得責任更為重大
(不能隨意胡言亂語了)

絞盡腦汁,今天來分享一個之前專案上的特殊需求
雖然隨著改版後邏輯簡化,所以應用不上
但這樣的需求或許未來也會有人有
所以分享給大家

中文翻譯為 如何混合無限的Array
其實我想了半天,一直不曉得要怎麼好好描述這個方法
還是直接看例子,假設我有陣列A

A = [[a,b,c],[1,2]]
A.do_something
=> [[a,1],[a,2],[b,1],[b,2],[c,1],[c,2]]

依照例子可以看出,就是將陣列裡面的小陣列,依序配對產生新的陣列組
如果說更複雜一點

A = [[a,b,c],[1,2],[x,y]]
A.do_something
=> [[a,1,x],[a,2,x],[b,1,x],[b,2,x],[c,1,x],[c,2,x],[a,1,y],[a,2,y],[b,1,y],[b,2,y],[c,1,y],[c,2,y]]

沒記錯的話,ruby或rails的Array當然是沒提供這麼方便的方法
假如沒有也只能自己寫(或是可以當作挑戰寫寫看)
當時卡了一天多,最後是被公司的一個資深前輩花了一個晚上解出來
原本的備案是限制數量,讓他最多只能在五組以內

如果你有自己試著解開,也可以晚一點再往下看我的解法


解法如下:

def speks_array_magic(array)
    # arr = [["1","2"],["3","4"]..]
    temp_result
    final_result = []
    # 特例:只有一種規格,如[["1","2"...]]
    if arr.length == 1
        final_result = arr.flatten
    else
        arr.each do |v|
            if arr[0] == v
                temp_result = v
            else
                temp_result = temp_result.product(v)
            end
        end
        temp_result.each do |v|
            final_result << v.flatten
        end
    end
    final_result
end

為了避免篇幅過短,這邊介紹一下用到的幾種Array method

flatten

英文是壓平的意思,可以把多重Array壓縮為一階
例如

[[0,1,2],[1,2,3]].flatten
=> [0, 1, 2, 1, 2, 3] 

product

英文大家都很熟悉,但卻是不熟悉的一個Array方法
其實這個方法跟需求有點接近,可惜無法直接使用
效果如下:

[1,2,3].product([4,5])     #=> [[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]]
[1,2].product([1,2])       #=> [[1,1],[1,2],[2,1],[2,2]]
[1,2].product([3,4],[5,6]) #=> [[1,3,5],[1,3,6],[1,4,5],[1,4,6],
                           #     [2,3,5],[2,3,6],[2,4,5],[2,4,6]]
[1,2].product()            #=> [[1],[2]]
[1,2].product([])          #=> []

但顯然這只能做到一對一的陣列,面對複數以上層級或是層級不固定時
就無能為力

透過這兩種方法,就能實作原本這看似不困難
卻天殺的難以實作的方法
未來應該會考慮包成Gem吧
感謝各位支持


上一篇
方便的lonely opperate
下一篇
如何編寫一個自己的Gem
系列文
Ruby礦工的Rails地圖30

尚未有邦友留言

立即登入留言