Qual é o código mais simples e sem bibliotecas para implementar interseções de matriz em javascript? eu quero escrever
intersection([1,2,3], [2,3,4,5])
e pegue
[2, 3]
Qual é o código mais simples e sem bibliotecas para implementar interseções de matriz em javascript? eu quero escrever
intersection([1,2,3], [2,3,4,5])
e pegue
[2, 3]
break
paraSimple js loops
aumenta os ops / seg para ~ 10MRespostas:
Use uma combinação de
Array.prototype.filter
eArray.prototype.indexOf
:Ou, como vrugtehagel sugeriu nos comentários, você pode usar o mais recente
Array.prototype.includes
para um código ainda mais simples:Para navegadores mais antigos:
fonte
intersection([1,2,1,1,3], [1])
retorna[1, 1, 1]
. Não deveria retornar apenas[1]
?array2.indexOf(n) != -1
um também pode escreverarray2.includes(n)
para um código ainda mais simples.Destrutivo parece mais simples, especialmente se pudermos assumir que a entrada está classificada:
Não destrutivo deve ser um cabelo mais complicado, pois precisamos rastrear índices:
fonte
intersect_safe
:length
é uma propriedade em Arrays, não um método. Há uma variável não danificadai
emresult.push(a[i]);
. Finalmente, isso simplesmente não funciona no caso geral: dois objetos em que nenhum é maior que o outro de acordo com o>
operador não são necessariamente iguais.intersect_safe( [ {} ], [ {} ] )
, por exemplo, fornecerá (assim que os erros mencionados anteriormente forem corrigidos) uma matriz com um elemento, o que está claramente errado..slice(0)
para criar um clone da matrizintersect_safe
, em vez de rastrear índices.Se o seu ambiente suportar o ECMAScript 6 Set , uma maneira simples e supostamente eficiente (consulte o link da especificação):
Mais curto, mas menos legível (também sem criar a interseção adicional
Set
):Evitando um novo
Set
deb
cada vez:Observe que, ao usar conjuntos, você obterá apenas valores distintos, sendo
new Set[1,2,3,3].size
avaliado como3
.fonte
[...setA]
sintaxe? Algum tipo especial de operação javascript?x => new Set(b).has(x)
função de seta não se transformab
em um conjunto toda vez que é executada? Você provavelmente deve salvar esse conjunto em uma variável.Usando Underscore.js ou lodash.js
fonte
Minha contribuição nos termos do ES6. Em geral, ele encontra a interseção de uma matriz com um número indefinido de matrizes fornecidas como argumentos.
fonte
[[0,1,2,3,4,5,6,7,8,9],[0,2,4,6,8],[4,5,6,7],[4,6]]
e depois se aplica.reduce()
. A primeira[0,1,2,3,4,5,6,7,8,9].filter( e => [0,2,4,6,8].includes(e)
operação é executada e o resultado torna-se novop
ec
torna - se[4,5,6,7]
no próximo turno e continua assim até que não resta maisc
.prototype
desnecessariamente.Eu recomendo a solução sucinta acima, que supera outras implementações em entradas grandes. Se o desempenho em pequenas entradas for importante, verifique as alternativas abaixo.
Alternativas e comparação de desempenho:
Consulte o seguinte snippet para implementações alternativas e consulte https://jsperf.com/array-intersection-comparison para obter comparações de desempenho.
Mostrar snippet de código
Resultados no Firefox 53:
Ops / s em matrizes grandes (10.000 elementos):
Ops / s em pequenas matrizes (100 elementos):
fonte
intersect([1,2,2,3], [2,3,4,5])
retorna[2, 2, 3]
.a.filter(b.includes)
. Ele deve executar consideravelmente mais rápido (o mesmo que sua atualização de função).Que tal usar apenas matrizes associativas?
editar:
fonte
Object.prototype
.d[b[i]] = true;
vez ded[b[j]] = true;
(i
nãoj
). Mas editar requer 6 caracteres.Algo parecido com isto, mas não testado bem.
PS: o algoritmo destinado apenas a números e seqüências normais, a interseção de matrizes de objetos arbitrários pode não funcionar.
fonte
O desempenho da implementação do @ atk para matrizes classificadas de primitivas pode ser aprimorado usando .pop em vez de .shift.
Criei um benchmark usando jsPerf: http://bit.ly/P9FrZK . É cerca de três vezes mais rápido para usar .pop.
fonte
a[aLast] > b[bLast]
pora[aLast].localeCompare(b[bLast]) > 0
(e o mesmo com oelse if
abaixo), isso funcionará em cadeias..pop
é O (1) e.shift()
é O (n)Usando jQuery :
fonte
c = $(b).filter(a);
, mas eu não recomendaria confiar no jQuery para esse tipo de manipulação de matriz, pois a documentação menciona apenas que funciona para elementos.Para matrizes que contêm apenas strings ou números, você pode fazer algo com a classificação, conforme algumas das outras respostas. Para o caso geral de matrizes de objetos arbitrários, não acho que você possa evitar fazê-lo pelo longo caminho. A seguir, será apresentada a interseção de qualquer número de matrizes fornecidas como parâmetros para
arrayIntersection
:fonte
firstArr
oufirstArray
não a variável e não atualizei todas as referências. Fixo.É bem curto usando ES2015 e Sets. Aceita valores do tipo Array como uma String e remove duplicatas.
fonte
Você pode usar um a
Set
partirthisArg
deArray#filter
e receberSet#has
como retorno de chamada.fonte
Um pequeno ajuste no menor aqui (a solução filter / indexOf ), ou seja, criar um índice dos valores em uma das matrizes usando um objeto JavaScript, reduzirá de O (N * M) para "provavelmente" tempo linear. source1 source2
Esta não é a solução mais simples (é mais código do que filter + indexOf ), nem é a mais rápida (provavelmente mais lenta por um fator constante do que intersect_safe () ), mas parece ser um bom equilíbrio. É no muito lado simples, oferecendo um bom desempenho, e não requer entradas pré-ordenada.
fonte
Outra abordagem indexada capaz de processar qualquer número de matrizes de uma vez:
Funciona apenas para valores que podem ser avaliados como strings e você deve transmiti-los como uma matriz como:
... mas aceita objetos de forma transparente como parâmetro ou como qualquer um dos elementos a serem cruzados (sempre retornando uma matriz de valores comuns). Exemplos:
Edição: Acabei de perceber que isso é, de certa forma, um pouco buggy.
Ou seja: eu o codifiquei pensando que matrizes de entrada não podem conter repetições (como o exemplo fornecido não).
Mas se matrizes de entrada contiverem repetições, isso produziria resultados errados. Exemplo (usando a implementação abaixo):
Felizmente, isso é fácil de corrigir, basta adicionar a indexação de segundo nível. Isso é:
Mudança:
de:
...e:
de:
Exemplo completo:
fonte
var v =
linha, adicioneif (typeof v == 'function') continue;
e ela pulará a adição de funções aos resultados. Obrigado!if (typeof v == 'function')
, poderemos usar sua stringification (v.toString()
) como chave para o índice. Mas precisamos fazer algo para preservá-lo intacto. A maneira mais fácil de fazer isso é simplesmente atribuir a função original como valor, em vez de um simples valor verdadeiro booleano, mas, nesse caso, a mais recente desindexação também deve ser alterada para detectar essa condição e restaurar o valor correto (a função).Você pode usar (para todos os navegadores, exceto o IE):
ou para o IE:
fonte
fonte
Com algumas restrições em seus dados, você pode fazer isso de forma linear tempo !
Para números inteiros positivos : use uma matriz que mapeie os valores para um booleano "visto / não visto".
Existe uma técnica semelhante para objetos : pegue uma chave fictícia, defina-a como "true" para cada elemento da matriz1 e, em seguida, procure essa chave nos elementos da matriz2. Limpe quando terminar.
Claro que você precisa ter certeza de que a chave não apareceu antes, caso contrário você estará destruindo seus dados ...
fonte
Contribuirei com o que tem funcionado melhor para mim:
fonte
"indexOf" para IE 9.0, chrome, firefox, opera,
fonte
fonte
Uma abordagem funcional com o ES2015
Uma abordagem funcional deve considerar o uso apenas de funções puras, sem efeitos colaterais, cada uma delas relacionada apenas a um único trabalho.
Essas restrições aprimoram a composibilidade e a reutilização das funções envolvidas.
Observe que o
Set
tipo nativo é usado, com um desempenho de pesquisa vantajoso.Evite duplicatas
Obviamente, os itens de ocorrência repetida do primeiro
Array
são preservados, enquanto o segundoArray
é desduplicado. Este pode ser ou não o comportamento desejado. Se você precisar de um resultado exclusivo, basta aplicardedupe
ao primeiro argumento:Calcule a interseção de qualquer número de
Array
sSe você deseja calcular a interseção de um número arbitrário de
Array
s, basta comporintersect
comfoldl
. Aqui está uma função de conveniência:fonte
(expr ? true : false)
é redundante. Use apenasexpr
se os booleanos reais não forem necessários, apenas verdade / falsidade.Pela simplicidade:
Benefícios:
Desvantagens:
Você não gostaria de usar isso para o mecanismo 3D ou o trabalho do kernel, mas se tiver problemas para executar isso em um aplicativo baseado em eventos, seu design terá problemas maiores.
fonte
.reduce
para construir um mapa e.filter
encontrar a interseção.delete
dentro do.filter
permite tratar a segunda matriz como se fosse um conjunto único.Acho essa abordagem bastante fácil de raciocinar. Ele executa em tempo constante.
fonte
Este é provavelmente o mais simples, além do list1.filter (n => list2.includes (n))
fonte
Se você precisar lidar com a interseção de várias matrizes:
fonte
ES6 estilo maneira simples.
Exemplo:
fonte
Eu escrevi uma função de interseção que pode até detectar interseção de matriz de objetos com base na propriedade particular desses objetos.
Por exemplo,
e queremos interseção com base na
id
propriedade, a saída deve ser:Como tal, a função para o mesmo (nota: código ES6) é:
e você pode chamar a função como:
Observe também: essa função encontra interseção, considerando que a primeira matriz é a matriz primária e, portanto, o resultado da interseção será o da matriz primária.
fonte
Acho que isso será mais rápido com o tempo O (array1 + array2) assumindo que map.has () é ~ O (1). Corrija-me se estiver errado.
fonte
Aqui está a implementação do underscore.js :
Fonte: http://underscorejs.org/docs/underscore.html#section-62
fonte