Как получить всю комбинацию значений из строк 2D-массива с помощью JavaScript? - PullRequest
0 голосов
/ 24 мая 2019

2D-массив, с которым я работаю, имеет разную длину для каждой строки, например:

var a = [2, 5, -12, 9];
var b = [54.0, 0.3];
var c = ["tree", "sun", "pool"]
var all = [a, b, c]

Любая строка в 2D-массиве иногда может быть нулевой. Массив вышеЭто всего лишь пример.

Я хочу получить по одному значению из каждой строки для каждого, сделать что-нибудь с этим значением, затем получить другую комбинацию значений и т. д.

Пример:

//IF ALL ROWS HAVE CONTENT
var values = [all[0][0], all[1][0], all[2][0]];
//do something with it
values = [all[0][0], all[1][0], all[2][1]];
//do something with it
......
values = [all[0][3], all[1][1], all[2][2]];
//do something with it

//IF FIRST AND THRID ROWS HAVE CONTENT, THE SAMPLE OUTPUT
var values = [all[0][0], all[2][0]];
values = [all[0][0], all[2][1]];
......
values = [all[0][3], all[2][2]];

//IF ONLY SECOND ROWS HAVE CONTENT, THE SAMPLE OUTPUT
var values = [all[1][0]];
values = [all[1][1]];

Вот мои мысли о логическом потоке кодов

//count how many rows are not empty
var arrayCount = 0;
for(var i=0; i < all.length; i++){
   if(all[i].length !== 0){
      arrayCount++;
  }
}
//store the combination of values each time
var values = [];
//reference for rows
var x; var y;
//differentiate the looping based on the number of unempty rows
switch(arrayCount){
   //one unempty row
   case 1:
      //figure out which one is not empty and set a's pointer to it
      for(var q = 0; q < x.length; q++){
         values.push(x[q]);
         //do something with it
         values.splice(1, 0);
      }
      break;
   case 2:
      //figure out which one are not empty and set a and b's pointer to them (don't know how, maybe using two loops for each row?)
      for(var q = 0; q < x.length; q++){
         values.push(x[q]);
         for(var p = 0; p < y.length; p++){
            values.push(y[p]);
            //do something with it
            values.splice(1, 1);
         }
         values.splice(1, 0);
      }
      break;
   case 3:
      //set pointers to all the rows
      for(var q = 0; q < x.length; q++){
         values.push(x[q]);
         for(var p = 0; p < y.length; p++){
            values.push(y[p]);
            for(var r = 0; r < z.length; r++){
               values.push(z[r]);
               //do something with it
               values.splice(1, 2);
            }
            values.splice(1, 1);
         }
         values.splice(1, 0);
      }
      break;
}

Боюсь, что весь код слишком длинный и имеет некоторые дубликатыкоды в коммутаторе.Можно ли это упростить?

Я видел сообщение с тем же вопросом и пытался ответить на него.К сожалению, платформа, на которой я пишу код (Fandom), не поддерживает эту функцию генератора.Я спросил, это только поддержка Javascript до ES3 или ES4.

Спасибо, что посмотрели на этот вопрос!

Ответы [ 3 ]

0 голосов
/ 24 мая 2019

Вы можете принять рекурсивный подход, взяв массив массивов, итерируя каждый внутренний массив и передавая массив собранных элементов, пока не останется больше массивов.

function getCartesian(array) {
    function iter(temp)  {
        var i = temp.length, j;
        if (i >= array.length) {
            return result.push(temp);
        }
        for (j = 0; j < array[i].length; j++) {
            iter(temp.concat(array[i][j]));
        }
    }

    var result = [];
    iter([]);
    return result;
}

console.log(getCartesian([[2, 5, -12, 9], [54.0, 0.3], ["tree", "sun", "pool"]]).map(a => a.join(' ')));
.as-console-wrapper { max-height: 100% !important; top: 0; }

с одной функцией

function getCartesian(array) {
    var i, j,
        first = array.shift(),
        temp = [],
        result = [];

    if (!first) return;
    if (!array.length) return first;
    temp = getCartesian(array);

    for (i = 0; i < first.length; i++)
        for (j = 0; j < temp.length; j++)
            result.push([first[i]].concat(temp[j]));

    return result;
}

console.log(getCartesian([[2, 5, -12, 9], [54.0, 0.3], ["tree", "sun", "pool"]]).map(a => a.join(' ')));
.as-console-wrapper { max-height: 100% !important; top: 0; }
0 голосов
/ 25 мая 2019

Я набрал этот ответ на похожий вопрос через онлайн-реплан Babel и получил уродливый, но рабочий код, который, кажется, делает то, что вы хотите.

Предупреждение: это ссылка Symbol.iterator, которая может быть недоступна в ES4. Я не исследовал это. Приведенная выше ссылка на babel включает в себя оригинальное решение и эту процедуру, если вы хотите поработать с настройками babel для совместимости.

Я не публиковал это изначально, потому что похоже, что люди уже ответили на ваш вопрос, используя тот же алгоритм, без уродливости переноса, но так как вы спросили ...

Вот результат, работающий с вашим примером ввода:

const a = [2, 5, -12, 9];
const b = [54.0, 0.3];
const c = ["tree", "sun", "pool"];
const all = [a, b, c];

function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }

function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); }

function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); }

function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }

var makeCartesian = function makeCartesian() {
  var t = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
  return function (a) {
    for (var _len = arguments.length, more = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
      more[_key - 1] = arguments[_key];
    }

    return a === undefined ? [t] : a.flatMap(function (x) {
      return makeCartesian([].concat(_toConsumableArray(t), [x])).apply(void 0, more);
    });
  };
};

var cartesian = makeCartesian();
console.log(cartesian.apply(void 0, _toConsumableArray(all)));
0 голосов
/ 24 мая 2019

Вот решение, которое обрабатывает пустые массивы и не использует функции генератора.

var combinations = all.reduce(function (previous, current) {

    if (current.length === 0)
        return previous;

    if (previous.length === 0)
        return current;

    const accumulate = current.map(function (x){

        return previous.map(function(y) {

            // Make one array if the accumulated result is an array
            if (y.length > 0)
                return y.concat(x);

            return [x, y];
        });
    });

    // Flatten combinations
    return accumulate.reduce( function (acc, x) {
        return acc.concat(x);
    });
});
...