多個數組的組合排序算法


一,聊騷:

我是一個喜歡直奔主題的人,不喜歡把時間浪費到廢話上,因為這也是在浪費讀者到時間,那為什么我今天一反常態,要說點聊騷的話呢?

緣由是這樣的,作為一個自學成才(其實還沒有成才)的前端人員來說,前端之路是多么的坎坷,面對大量的前端知識,面對如雨后春筍般的前端框架的興起,面對nodejs在前端與后端之間的連接的應用,

此時的前端再也不是幾年前的那個前端了,有太多的框架要去學,有太多的前端知識要去研究,學習,這樣難免會讓人失去方向,學的東西也很雜,為了適應現在的對前端人員的要求,你就不得不撒開網去

探索,導致的結果就是,你好像什么都接觸過,感覺什么都懂,但是如果要你說出一個所以然來,好像又什么都不懂,這才是前端學習最可怕的,浮於表面,沒有真正深入了解其中的原理,有人會說,現在的技術學習曲線那么陡,要學的知識那么多,哪有那么多時間去學呢?

回答這個問題,我得先說,我失業了,就如同我前面說的一樣,我只是浮於表面,沒有真正沉下去,那怎么才能學好技術呢?根據牛人的指導,大致是在技術選型上,選擇適合自己的,比如說前端框架,angularjs,reactjs,backbonejs,vuejs等等,選擇一個自己覺得比較好上手的,然后搭配一個打包工具,比如webpack,gulp,grunt等等,多去深入理解它的實現原理,編寫的思想,總之,多看,

多寫(這才是重點),多研究,然后把自己的心得感悟,以筆記或者博客的形式記錄下來,讓牛人們幫你噴噴,這樣既可以加深印象,還可以和牛人一起學習,算了,不說了,這其實是寫給我看的。

二,正題:

言歸正傳,今天我們要講的是一個什么命題呢?

命題:多維數組的排列組合 或 多個數組之間的排列組合

命題場景:

現在有一批手機,其中顏色有['白色','黑色','金色'];內存大小有['16G','32G','64G'],版本有['移動','聯通','電信'],要求寫一個算法,實現[['白色','16G','移動'], ['白色','16G','聯通'] ...]這樣的組合,擴張,如果后面還有參數,比如再加一個['國行','港版'],不改程序一樣可以執行!

不知道要實現的需求大家聽懂了沒有,下面我會一步步實現,教大家怎么寫:

最后得到的結果是一個數組里面包含若干個數組,看着挺復雜的,我們先實現一個簡化版的,數組里面不是數組,而是字符串連接的結果,嗯,先一步步來吧:

第一步,想想通過什么技術來實現,你看這數組之間不斷的重組,很容易想到用回調函數,一遍一遍的執行,大致知道用什么技術,接下來就是寫思路了,看看下面:

// 執行組合排列的函數
    function doExchange(arr){ } //執行
    var arr = [['a', 'b', 'c'], [1, 2, 3], ['x', 'y', 'z']]; var arr1 = [['a','b','c']]; //doExchange(arr);
    console.log(doExchange(arr));

 

吶,我們建一個函數doExchange(),表示我們執行排序的主函數,然后當執行arr的時候,輸出['a1x','a1y' ...]這樣的結果,如果是arr1呢?我們需要輸出['a','b','c'],這好理解哈,現在的重點就是這個主函數了,下面主要講主函數的實現過程

// 執行組合排列的函數
    function doExchange(arr){ var len = arr.length; // 當數組大於等於2個的時候
        if(len >= 2){ }else{ return arr[0]; } }

 

我們的思路是,當參數里面的數組長度大於2個,比如2個,3個或更多,就執行我們的組合代碼,否則只有一個,就直接輸出來唄

如果是大於2個呢?我們的思路是先進行第一個和第二個的合並,網上有一種實現方式是,用多層for循環來嵌套,最終得到組合的值,這種估計大家也能感覺到,兩三個還可以,多了就呵呵了,這里只是提一下,因為前兩個比較好獲取,合並之后呢,就相當於是

2個數組合並成一個數組,然后這個數組再放倒參數數組中第一個位置,把原來前兩個去掉,相當於是用這個數組替換前兩個,沒聽懂哈,沒關系,我們直接看代碼:

if(len >= 2){ // 第一個數組的長度
            var len1 = arr[0].length; // 第二個數組的長度
            var len2 = arr[1].length; // 2個數組產生的組合數
            var lenBoth = len1 * len2; // 申明一個新數組,做數據暫存
            var items = new Array(lenBoth); // 申明新數組的索引
            var index = 0; // 2層嵌套循環,將組合放到新數組中
            for(var i=0; i<len1; i++){ for(var j=0; j<len2; j++){ items[index] = arr[0][i] + arr[1][j]; index++; } } }

 

吶,這里我們先獲取第一個和第二個數組的長度,然后計算出它們有多少種組合方式,然后新建一個暫存的數組,用來存我們組合得到的結果,后面就是用雙層循環,做字符串連接,放到暫存數組中,沒什么好說的

我們的到了前兩個的組合結果,依據我們的思路,是要把它和原來數組合並成一個新數組

// 第一個數組的長度
            var len1 = arr[0].length; // 第二個數組的長度
            var len2 = arr[1].length; // 2個數組產生的組合數
            var lenBoth = len1 * len2; // 申明一個新數組,做數據暫存
            var items = new Array(lenBoth); // 申明新數組的索引
            var index = 0; // 2層嵌套循環,將組合放到新數組中
            for(var i=0; i<len1; i++){ for(var j=0; j<len2; j++){ items[index] = arr[0][i] + arr[1][j]; index++; } } // 將新組合的數組並到原數組中
            var newArr = new Array(len -1); for(var i=2;i<arr.length;i++){ newArr[i-1] = arr[i]; } newArr[0] = items;

 

整體的思路就是這樣,得到的新數組就是剩下的未組合的數組了,到這里大家應該就豁然開朗了,然后使用遞歸再次調用這個過程,這樣不斷組合成新數組,那這個新數組當參數時,如果數組的長度等於1了,就說明組合完了,就會執行后面的else語句,輸出出來。

整體代碼貼出來感受一下:

// 執行組合排列的函數
    function doExchange(arr){ var len = arr.length; // 當數組大於等於2個的時候
        if(len >= 2){ // 第一個數組的長度
            var len1 = arr[0].length; // 第二個數組的長度
            var len2 = arr[1].length; // 2個數組產生的組合數
            var lenBoth = len1 * len2; // 申明一個新數組,做數據暫存
            var items = new Array(lenBoth); // 申明新數組的索引
            var index = 0; // 2層嵌套循環,將組合放到新數組中
            for(var i=0; i<len1; i++){ for(var j=0; j<len2; j++){ items[index] = arr[0][i] + arr[1][j]; index++; } } // 將新組合的數組並到原數組中
            var newArr = new Array(len -1); for(var i=2;i<arr.length;i++){ newArr[i-1] = arr[i]; } newArr[0] = items; // 執行回調
            return doExchange(newArr); }else{ return arr[0]; } } //執行
    var arr = [['a', 'b', 'c'], [1, 2, 3], ['x', 'y', 'z']]; var arr1 = [['a','b','c']]; //doExchange(arr);
    console.log(doExchange(arr));

執行arr和arr1的結果給大家截個圖吧:

我們簡化版的組合算是完成了,可能也會有類似的需求,但是我們今天要講的不是這樣的需求,而是里面的每一個組合要是一個數組,這個怎么實現呢?

突破點應該就在字符串連接那塊了,原來是用的字符串連接,如果我們改成數組連接,不就行了嗎?試試:

for(var i=0; i<len1; i++){ for(var j=0; j<len2; j++){ if(arr[0][i] instanceof Array){ items[index] = arr[0][i].concat(arr[1][j]); }else{ items[index] = [arr[0][i]].concat(arr[1][j]); } index++; } }

 

其他地方都沒有改,就只是改了這里,但是這里第一次是要做數組判斷的,因為剛開始是字符串,要轉換成數組才能連接,這里注意一下,最終的代碼如下:

function doExchange(arr){ var len = arr.length; // 當數組大於等於2個的時候
        if(len >= 2){ // 第一個數組的長度
            var len1 = arr[0].length; // 第二個數組的長度
            var len2 = arr[1].length; // 2個數組產生的組合數
            var lenBoth = len1 * len2; // 申明一個新數組
            var items = new Array(lenBoth); // 申明新數組的索引
            var index = 0; for(var i=0; i<len1; i++){ for(var j=0; j<len2; j++){ if(arr[0][i] instanceof Array){ items[index] = arr[0][i].concat(arr[1][j]); }else{ items[index] = [arr[0][i]].concat(arr[1][j]); } index++; } } var newArr = new Array(len -1); for(var i=2;i<arr.length;i++){ newArr[i-1] = arr[i]; } newArr[0] = items; return doExchange(newArr); }else{ return arr[0]; } } //     var arr = [['a', 'b', 'c'], [1, 2, 3], ['x', 'y', 'z'],['手機']]; var arr1 = [['a','b','c']]; console.log(doExchange(arr));

 

得到的結果:

我后面又加了一個手機,同樣是可以實現的,到這里就算死寫完了。

 

三,總結:

給個總結吧,這個算法剛開始想想,感覺挺復雜的,這么多數組要排列組合,但是我們將它化繁為簡,比如說就當只有2個數組的組合,是不是就簡單多了,這個實現了,然后考慮多組的,這樣世界就清靜了!還是那句話,還是多寫吧!

歡迎轉載,原創不易,轉載時請注明出處,謝謝!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM