Какая хорошая реализация математических наборов в JavaScript?

Где хорошая реализация математических наборов для JavaScript? Он должен включать эффективные реализации пересечения, объединения, дополнения и (за бонусные баллы) декартово произведение.

Нет, это не домашнее задание. У меня есть yubikey, это USB-клавиатура, которая набирает последовательность, выбранную из 16 кодов клавиш, для ввода 128-битного одноразового пароля (otp). Чтобы сделать его более полезным, программное обеспечение должно определять раскладку клавиатуры на основе созданных символов и сопоставлять эти символы с тем, что они будут в раскладке «нас» для совместимости с существующим бэкэндом.

Итак, у меня есть 93 различных последовательности из 16 символов, представляющих все, что может набрать yubikey в каждой из 430 раскладок клавиатуры. (Для этой цели многие макеты одинаковы.) Возможные сопоставления для конкретного otp — это каждая 16-символьная последовательность, содержащая каждый символ otp.

Чтобы найти это эффективно, я использую обратный индекс, сопоставляющий каждый возможный символ со списком раскладок клавиатуры, которые используют этот символ. Ответ — это пересечение каждой записи обратного индекса для каждого уникального символа в отп. Это почти всегда заканчивается ровно 1 элементом.

Было бы проще написать этот кроссбраузер с хорошей реализацией Set().

Код пока находится по адресу http://dingoskidneys.com/~dholth/yubikey/.


person joeforker    schedule 12.08.2009    source источник
comment
Нет. Я реализовывал инвертированный индекс, нуждался в хорошем методе пересечения множества, и все те, которые я нашел, были отстойными.   -  person joeforker    schedule 12.08.2009


Ответы (7)


Я не знаю каких-либо существующих реализаций, но если ваши элементы набора являются строками (или имеют уникальное строковое представление), вы можете довольно легко использовать объекты JavaScript. Элементы будут свойствами объекта, а значение может быть любым.

// Make a set from an array of elements
function makeSet(items) {
    var set = {};
    for (var i = 0; i < items.length; i++) {
        set[items[i]] = true;
    }
    return set;
}

function copyInto(s, copy) {
    for (var item in s) {
        if (s[item] === true) {
            copy[item] = true;
        }
    }
}

function union(s1, s2) {
    var u = {};
    copyInto(s1, u);
    copyInto(s2, u);
    return u;
}

function intersection(s1, s2) {
    var i = {};
    for (var item in s1) {
        if (s1[item] === true && s2[item] === true) {
            i[item] = true;
        }
    }
    return i;
}

function difference(s1, s2) {
    var diff = {};
    copyInto(s1, diff);
    for (var item in s2) {
        if (s2[item] === true) {
            delete diff[item];
        }
    }
    return diff;
}

// etc.

Вы также можете использовать item in set или set.hasOwnProperty(item) вместо set[item] === true, но явно проверяя true, вы автоматически игнорируете любые функции, которые могут быть присоединены к объекту (в случае, если кто-то изменил Object.prototype или это не простой объект).

person Matthew Crumley    schedule 12.08.2009
comment
.hasOwnProperty будет безопаснее, чем set[item]===true нет? Не мог ли кто-нибудь добавить прототип со значением true? Object.prototype.x = true - person mpen; 18.07.2011
comment
@ Марк, да, hasOwnProperty было бы безопаснее для таких случаев, хотя это зависит от того, как вы хотите, чтобы он вел себя. В некоторых случаях вам может понадобиться, чтобы свойства из прототипа отображались в наборе. - person Matthew Crumley; 18.07.2011

Используя jPaq или другую библиотеку JavaScript, реализующую функции Array.prototype.reduce и Array.prototype.forEach, вы можете создайте декартову функцию произведения, которая принимает два или более массивов. Вот код функции, которая вычисляет декартово произведение двух или более массивов:

function cartesianProductOf() {
  return Array.prototype.reduce.call(arguments, function(a, b) {
    var ret = [];
    a.forEach(function(a) {
      b.forEach(function(b) {
        ret.push(a.concat([b]));
      });
    });
    return ret;
  }, [[]]);
}

Поскольку это находится в библиотеке, я открыт для предложений по именованию функции, чтобы я мог добавить ее в jPaq< /а>. Кстати, чтобы не заниматься плагиатом, мне пришла в голову идея использовать сокращение из этого сообщение.

person Chris West    schedule 11.04.2011

Использование метода сокращения Underscore.

function cartesianProductOf(){
    return _.reduce(arguments, function(mtrx, vals){
        return _.reduce(vals, function(array, val){
            return array.concat(
                _.map(mtrx, function(row){ return row.concat(val); })
            );
        }, []);
    }, [[]]);
}
person Ben at Qbox.io    schedule 28.10.2011

Sylvester — это хорошая библиотека для выполнения векторных и матричных вычислений в Javascript. Это единственная математическая библиотека, о которой я могу думать прямо сейчас.

person Josh Stodola    schedule 12.08.2009

Лично мне нравится, как это делается в jPaq (http://jpaq.org/documentation/Arrays+as+Sets/1.0/). Вот три примера, которые я успешно протестировал:

alert([1,2,3,4,5].subtract([2,3,5]));  // evaluates to [1,4]
alert([1,2,5].union([1,3,4,5]));  // evaluates to [1,2,5,3,4]
alert([1,2,3,5].intersect([0,1,2,4,6]));  // evaluates to [1,2]

Что хорошо в jPaq, так это то, что вы можете просто загрузить код этих трех функций. jPaq делает так, что вам не нужно загружать дополнительные материалы, которые вы все равно не будете использовать.

person Clarence Fredericks    schedule 16.03.2011
comment
Кроме того, стоит отметить, что в jPaq есть функция uniquify и для массивов. Чтобы загрузить это вместе с набором функций, вы можете перейти сюда: http://jpaq.org/download/1.0.1.0A. - person Clarence Fredericks; 17.03.2011

Я выполнил набор реализации на JavaScript, в основном связанный с эффективными операциями difference, intersection и union. Он доступен на GitHub. Форки и новые операции приветствуются! :-)

person mcrisc    schedule 06.01.2012
comment
Нужно ли сортировать коллекции в вашей реализации? Похоже, вы используете какой-то бинарный поиск в своей реализации, но не сломается ли он, если элементы не в порядке? - person pseudoramble; 18.12.2013
comment
Ты прав, Даг! Моя реализация сильно зависит от отсортированных коллекций. Это необходимо для использования бинарного поиска и для работы моего алгоритма пересечения. Но алгоритма сортировки нет, вместо этого элементы вставляются, чтобы убедиться, что все остальное будет работать. - person mcrisc; 30.12.2013

В программе, вызвавшей этот вопрос, набор представляет собой массив, а пересечение — это

s = [1,2,3];
q = [3,4,5];
sq = s.filter(function(x) {
    return q.indexOf(x) >= 0;
});

Конечно, это не работает в ie.

person joeforker    schedule 12.08.2009