Найти все перестановки предложений с синонимичными словами? [Дубликат]

Работа снизу вверх. Если вы удаляете строку, все перемещается вверх, и вы пропускаете эту строку на следующей итерации.

Вот «кишки» кода для обработки снизу.

With Worksheets("Sheet1")
    For rw = .Cells(.Rows.Count, "B").End(xlUp).Row To 2 Step -1
        Select Case UCase(.Cells(rw, "B").Value2)
            Case "FG", "QC", "CS"
                .Rows(rw).EntireRow.Delete
        End Select
    Next rw
End With
40
задан quano 8 March 2013 в 18:37
поделиться

8 ответов

Просто для удовольствия, вот более функциональный вариант решения в моем первом ответе:

function cartesian() {
    var r = [], args = Array.from(arguments);
    args.reduceRight(function(cont, factor, i) {
        return function(arr) {
            for (var j=0, l=factor.length; j<l; j++) {
                var a = arr.slice(); // clone arr
                a[i] = factor[j];
                cont(a);
            }
        };
    }, Array.prototype.push.bind(r))(new Array(args.length));
    return r;
}

Альтернативный, для полной скорости мы можем динамически скомпилировать наши собственные петли:

function cartesian() {
    return (cartesian.cache[arguments.length] || cartesian.compile(arguments.length)).apply(null, arguments);
}
cartesian.cache = [];
cartesian.compile = function compile(n) {
    var args = [],
        indent = "",
        up = "",
        down = "";
    for (var i=0; i<n; i++) {
        var arr = "$"+String.fromCharCode(97+i),
            ind = String.fromCharCode(105+i);
        args.push(arr);
        up += indent+"for (var "+ind+"=0, l"+arr+"="+arr+".length; "+ind+"<l"+arr+"; "+ind+"++) {\n";
        down = indent+"}\n"+down;
        indent += "  ";
        up += indent+"arr["+i+"] = "+arr+"["+ind+"];\n";
    }
    var body = "var res=[],\n    arr=[];\n"+up+indent+"res.push(arr.slice());\n"+down+"return res;";
    return cartesian.cache[n] = new Function(args, body);
}
68
ответ дан Bergi 22 August 2018 в 23:13
поделиться
  • 1
    Удивительно, спасибо. Бенчмарк доступен здесь: jsfiddle.net/9uvfP . Ваше решение занимает 0.14 секунды для запуска 100 000 раз, что делает его самой быстрой реализацией. :) – quano 9 March 2013 в 14:00
  • 2
    Ах, я заметил ошибку в тесте. Обновлено здесь: jsfiddle.net/2xt5F . Это занимает около 0,6 секунды. – quano 9 March 2013 в 14:13
  • 3
    Это похоже на подход, который я изначально принимал, но не мог туда добраться ... Немного сна, лишенного нового ребенка, но рад, что кто-то сделал это, чтобы я мог видеть! – Tom Pietrosanti 9 March 2013 в 16:00
  • 4
    Похоже, я стану вашим поклонником. Вы - гений. – BlitZ 26 March 2014 в 16:49
  • 5
    Несмотря на то, что ответ скрипта @ Neob91 для скриптов Fiddles является самым быстрым для меня, этот jsperf, кажется, предлагает, чтобы этот ответ был самым быстрым: jsperf.com/array-combos – maxedison 15 June 2015 в 14:59
  • 6
    блестящий! thankyou @Bergi, эта «полная скорость» хорошо работает (я еще не тестировал другую) – David Tew 27 July 2015 в 10:45
72
ответ дан Bergi 5 November 2018 в 20:50
поделиться

После небольшого исследования я обнаружил предыдущий связанный с ним вопрос: Поиск всех комбинаций значений массива JavaScript

Я адаптировал часть кода оттуда, чтобы он возвращался массив массивов, содержащий все перестановки:

function(arraysToCombine) {
    var divisors = [];
    for (var i = arraysToCombine.length - 1; i >= 0; i--) {
       divisors[i] = divisors[i + 1] ? divisors[i + 1] * arraysToCombine[i + 1].length : 1;
    }

    function getPermutation(n, arraysToCombine) {
       var result = [], 
           curArray;    
       for (var i = 0; i < arraysToCombine.length; i++) {
          curArray = arraysToCombine[i];
          result.push(curArray[Math.floor(n / divisors[i]) % curArray.length]);
       }    
       return result;
    }

    var numPerms = arraysToCombine[0].length;
    for(var i = 1; i < arraysToCombine.length; i++) {
        numPerms *= arraysToCombine[i].length;
    }

    var combinations = [];
    for(var i = 0; i < numPerms; i++) {
        combinations.push(getPermutation(i, arraysToCombine));
    }
    return combinations;
}

Я поместил рабочую копию в http://jsfiddle.net/7EakX/ , которая принимает массив, который вы ([[0,1], [0,1,2,3], [0,1,2]]) и выводит результат на консоль браузера.

3
ответ дан Community 22 August 2018 в 23:13
поделиться
  • 1
    Прекрасно работает. Я сделал контрольный показатель: jsfiddle.net/kLfq9 . Ваше решение занимает около 0,5 секунды для запуска 100 000 раз в Chrome на моем компьютере. – quano 9 March 2013 в 13:44

Я предлагаю простую рекурсивную функцию -генератора :

// Generate all combinations of array elements:
function* cartesian(head, ...tail) {
  let remainder = tail.length ? cartesian(...tail) : [[]];
  for (let r of remainder) for (let h of head) yield [h, ...r];
}


// Example:
for (let c of cartesian([0,1], [0,1,2,3], [0,1,2])) {
  console.log(...c);
}

5
ответ дан le_m 22 August 2018 в 23:13
поделиться
var f = function(arr){
    if(typeof arr !== 'object'){
        return false;
    }

    arr = arr.filter(function(elem){ return (elem !== null); }); // remove empty elements - make sure length is correct
    var len = arr.length;

    var nextPerm = function(){ // increase the counter(s)
        var i = 0;

        while(i < len)
        {
            arr[i].counter++;

            if(arr[i].counter >= arr[i].length){
                arr[i].counter = 0;
                i++;
            }else{
                return false;
            }
        }

        return true;
    };

    var getPerm = function(){ // get the current permutation
        var perm_arr = [];

        for(var i = 0; i < len; i++)
        {
            perm_arr.push(arr[i][arr[i].counter]);
        }

        return perm_arr;
    };

    var new_arr = [];

    for(var i = 0; i < len; i++) // set up a counter property inside the arrays
    {
        arr[i].counter = 0;
    }

    while(true)
    {
        new_arr.push(getPerm()); // add current permutation to the new array

        if(nextPerm() === true){ // get next permutation, if returns true, we got them all
            break;
        }
    }

    return new_arr;
};
2
ответ дан Neob91 22 August 2018 в 23:13
поделиться
  • 1
    Благодарю. Бенчмарк доступен здесь: jsfiddle.net/6cxEH . Ваше решение занимает около 0,6 секунды, чтобы работать 100 000 раз. – quano 9 March 2013 в 14:02
  • 2
    Я рад помочь и счастлив, что это эффективно. ;) – Neob91 10 March 2013 в 22:10

Вы можете использовать итеративный подход, создавая вспомогательные массивы.

var parts = [[0, 1], [0, 1, 2, 3], [0, 1, 2]],
    result = parts.reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []));

console.log(result.map(a => a.join(', ')));
.as-console-wrapper { max-height: 100% !important; top: 0; }

5
ответ дан Nina Scholz 22 August 2018 в 23:13
поделиться

Другая реализация с рекурсивным стилем ES6

Array.prototype.cartesian = function(a,...as){
  return a ? this.reduce((p,c) => (p.push(...a.cartesian(...as).map(e => as.length ? [c,...e] : [c,e])),p),[])
           : this;
};

console.log(JSON.stringify([0,1].cartesian([0,1,2,3], [[0],[1],[2]])));

1
ответ дан Redu 22 August 2018 в 23:13
поделиться

Вот еще один способ сделать это. Я обрабатываю индексы всех массивов, как число, чьи цифры имеют разные базы (например, время и даты), используя длину массива в качестве радиуса.

Итак, используя ваш первый набор данных , первая цифра является базой 2, вторая - базой 4, а третья - базой 3. Счетчик запускает 000, затем идет 001, 002, затем 010. Цифры соответствуют индексам в массивах, а так как порядок сохраняется, это не проблема.

У меня есть скрипка с ней, работающая здесь: http://jsfiddle.net/Rykus0/DS9Ea/1/

и вот код:

// Arbitrary base x number class 
var BaseX = function(initRadix){
    this.radix     = initRadix ? initRadix : 1;    
    this.value     = 0;
    this.increment = function(){
        return( (this.value = (this.value + 1) % this.radix) === 0);
    }
}

function combinations(input){
    var output    = [],    // Array containing the resulting combinations
        counters  = [],    // Array of counters corresponding to our input arrays
        remainder = false, // Did adding one cause the previous digit to rollover?
        temp;              // Holds one combination to be pushed into the output array

    // Initialize the counters
    for( var i = input.length-1; i >= 0; i-- ){
        counters.unshift(new BaseX(input[i].length));
    }

    // Get all possible combinations
    // Loop through until the first counter rolls over
    while( !remainder ){
        temp      = [];   // Reset the temporary value collection array
        remainder = true; // Always increment the last array counter

        // Process each of the arrays
        for( i = input.length-1; i >= 0; i-- ){
            temp.unshift(input[i][counters[i].value]); // Add this array's value to the result

            // If the counter to the right rolled over, increment this one.
            if( remainder ){
                remainder = counters[i].increment();
            }
        }
        output.push(temp); // Collect the results.
    }

    return output;
}

// Input is an array of arrays
console.log(combinations([[0,1], [0,1,2,3], [0,1,2]]));
2
ответ дан Tom Pietrosanti 22 August 2018 в 23:13
поделиться
  • 1
    Спасибо за решение. Бенчмарк доступен здесь: jsfiddle.net/XgyPC . Он выполняет вашу функцию 100 000 раз. Это занимает около 1 секунды на моем компьютере в Chrome. – quano 9 March 2013 в 13:45
  • 2
    Отлично! Благодарим вас за запуск теста. Мне было интересно, как это будет действовать, и не задумывался об этом. Это интересная небольшая проблема для решения, поэтому я могу дать ей еще один шаг. – Tom Pietrosanti 9 March 2013 в 15:57
Другие вопросы по тегам:

Похожие вопросы: