一個關於JS解決數組相乘問題

數組相乘,顧名思義就是將多個數組的每一元素乘(組合)起來。它的結果以幾何數級增加,初次遇到此類問題時,經常令人頭皮發麻,咱們如今以js的角度來解決這個問題。算法

從實例出發

衆所周知,女孩出門前通常須要通過精心打扮,那麼假設你有一個女友,她有着3頂帽子,5件衣服,5條褲子,3雙鞋子,2只口紅,4個包包,2副墨鏡,且心情可能會影響穿着,她可能由於心情很差而選擇不帶一些物品,可是她會告訴你她會穿戴什麼,要求列舉全部方案,看到題目後…… 數組

不說了,先將實際問題轉化成語言問題吧。
七個數組,分別表示七種穿戴,數組中存值爲該穿戴的代號,傳值爲字符串是她告訴你她須要的穿着,例"clothes trousers",中間以空格隔開

const hat = ['a','b','c'];
const clothes = ['0','1','2','3','4'];
const trousers = ['q','w','e','r','t'];
const shoes = ['A','B','C'];
const lipstick = ['$1','$2'];
const bag = ['¥1','¥2','¥3','¥4'];
const sunglasses = ['^1','^2'];
function getComb(str){
    return arr;
}
複製代碼

解決思路

秉着無論什麼問題,看到數組我就用循環的思路,去解題,不免會趕上不少問題。若是,題目上明確指出女友心情必須max每次出門都裝備拉滿,那ok沒問題,7次循環解決。可是女人心海底針吶,你只能經過她告訴的穿着來列舉(若是不管什麼狀況,你都用7次循環,那當我沒說)。bash

隨機數法

咱們可讓電腦本身隨機組合,並判斷若是已經添加過這個結果,就不加進數組就ok了。dom

const arr = str.split(' ')
    .map(name => {
        switch (name) {
            case 'hat': return hat;
            case 'clothes': return clothes;
            case 'trousers': return trousers;
            case 'shoes': return shoes;
            case 'lipstick': return lipstick;
            case 'bag': return bag;
            case 'sunglasses': return sunglasses;
        }
    })
複製代碼

先將傳入的字符串轉化一個與它傳值相關的二維數組,例:傳入"hat clothes"
arr爲[ [ 'a', 'b', 'c' ], [ '0', '1', '2', '3', '4' ] ],這樣咱們就得知了穿戴的數目,以及該穿戴的種類了。咱們不可貴出,這種狀況下最多能列出15種結果,定義一個total變量並修改一下上面代碼。函數

let total = 1;
const arr = str.split(' ')
    .map(name => {
        switch (name) {
            case 'hat': total *= hat.length ; return hat;
            case 'clothes': total *= clothes.length ; return clothes;
            case 'trousers': total *= trousers.length ; return trousers;
            case 'shoes': total *= shoes.length ; return shoes;
            case 'lipstick': total *= lipstick.length ; return lipstick;
            case 'bag': total *= bag.length ; return bag;
            case 'sunglasses': total *= sunglasses.length ; return sunglasses;
        }
    })
複製代碼

若是使用隨機數咱們就能將一個屢次循環轉化爲一個while判斷的for循環。咱們new一個數組result,因爲咱們知道一共有幾種結果,因此while循環的條件就是:result.length < total.ui

let result = [], sum = '';
    while (result.length < total) {
        for (let i = 0; i < arr.length; i++) {
            sum += arr[i][parseInt(Math.random() * arr[i].length)];
        }
        if (result.indexOf(sum) == -1)
            result.push(sum);
        sum = '';
    }
    return result;
複製代碼

注意:Math.random()是產生一個[0,1)的隨機浮點數,數組的索引是整數,因此咱們須要轉換類型;sum是數組的組合,因此咱們在添加完後須要了給它還原.spa

隨機數法的缺點:
算法過於暴力,因爲Math.random值返回的不肯定性,致使不少時間會浪費在生成一個數組已經添加過的值上。rest

reduce方法

咱們也可使用reduce方法很是簡便的完成數組的乘法.不少初學者可能會對reduce比較陌生,由於這是一個不常見的方法,可是使用reduce進行很方便,先簡單介紹一下reduce方法。code

reduce方法接收一個函數做爲累加器,數組中的每一個值(從左到右)開始縮減,最終爲一個值cdn

reduce 爲數組中的每個元素依次執行回調函數,不包括數組中被刪除或從未被賦值的元素,接受四個參數:初始值(或者上一次回調函數的返回值),當前元素值,當前索引,調用 reduce 的數組。

arr.reduce(callback,[initialValue])
callback (執行數組中每一個值的函數,包含四個參數)
previousValue (上一次調用回調返回的值,或者是提供的初始值(initialValue))
currentValue (數組中當前被處理的元素)
index (當前元素在數組中的索引)
array (調用 reduce 的數組)
initialValue (做爲第一次調用 callback 的第一個參數。)
複製代碼

基礎用法

const a = [1,2,3,4,5,6];
    const rst = a.reduce((pre,cur)=>{
        return pre + cur;
    })
    console.log(rst); // rst = 1+2+3+4+5+6
複製代碼

pre爲第一個值或上次計算的結果,這裏沒有傳初值,pre初始默認爲0,cur爲數組的每個值。這裏解析過程:

=> pre = 0 ; cur = a[0];
=> pre = 0 + a[0] ; cur = a[1];
=> pre = 0 + a[0] + a[1] ; cur = a[2];
...
rst = 0 + 1 + 2 + 3 + 4 + 5 + 6 // 21
複製代碼

用reduce解決數組相乘

return arr.reduce((pre,cur)=>{
        return [].concat(...pre.map(e=>cur.map(ele=>ele+e)))
    }) 
複製代碼

例:

str = 'clothes hat bag';
=> arr :
[ [ '0', '1', '2', '3', '4' ],
  [ 'a', 'b', 'c' ],
  [ '¥1', '¥2', '¥3', '¥4' ] ]
複製代碼

首先將一個複雜組合問題,轉化爲疊加組合問題。若是能將arr[0],arr[1]兩個組合的結果返回給pre,那麼咱們就能經過兩兩組合來完成複雜組合。接下來使用map完成兩兩組合:

pre : [ '0', '1', '2', '3', '4' ]
cur : [ 'a', 'b', 'c' ]
pre.map(e => cur.map(ele => e + ele));
/*第一次*/
e : '0' , ele: 'a' , e + ele ='0a', pre[['0a']]
e : '0' , ele: 'b' , e + ele = '0b', pre[['0a','0b']]
...
/*結束*/
pre[['0a','0b','0c'],['1a','1b','1c'],['2a','2b','2c'],['3a','3b','3c'],['4a','4b','4c' ]]
cur : [ '¥1', '¥2', '¥3', '¥4' ]
複製代碼

接下來咱們只須要將二維數組pre轉化爲一維數組,而後函數就會隨着reduce一步一步將數組相乘起來了

[].concat[...pre.map(e => cur.map(ele => e + ele))]
複製代碼

擴展運算符( spread )是三個點(...)。它比如 rest 參數的逆運算,將一個數組轉爲用逗號分隔的參數序列,通常在傳參時使用。

到這裏咱們就解決這個女友出門的問題了。

相關文章
相關標籤/搜索