消除多个阵列的重复

时间:2017-06-02 14:20:39

标签: javascript

我有3个阵列:

array1 = [ 'A', 'B', 'A', 'B']
array2 = [   5,   5,   7,   5]
array3 = [true,true,true,true]

我想知道是否有任何简单的方法(可能使用lodash)来消除重复并以此结束:

array1 = [ 'A', 'B', 'A']
array2 = [   5,   5,   7]
array3 = [true,true,true]

我知道我可以做一个函数并比较之前的值,但是有更聪明的方法吗?

更新 请注意,我不需要消除每个数组的重复项。 我所期待的是一种消除重复“垂直”的方法

更新2 请注意,每个“列”都是一个记录。 record1 = ['A',5,true] record2 = ['B',5,true] record3 = ['A',7,true] record1 = ['B',5,true]

7 个答案:

答案 0 :(得分:4)

TL; DR

const records = array1.map((a, i) => [a, array2[i], array3[i]]);

const index = {};
records.filter(column => {
  const key = JSON.stringify(column);
  return key in index ? false : index[key] = true;
});

咦?

有很多方法可以解决这个问题,效率会有不同程度,最佳解决方案取决于数据的大小。一个简单但天真的解决方案遍历每个“列”并检查所有前面的列是否相等。它看起来像这样:

const array1 = [ 'A', 'B', 'A', 'B'];
const array2 = [   5,   5,   7,   5];
const array3 = [true,true,true,true];

const newArray1 = array1.slice(0,1); // column 0 is never duplicate
const newArray2 = array2.slice(0,1);
const newArray3 = array3.slice(0,1);

// loop over columns starting with index 1
outer: for (let i = 1; i < array1.length; i++) {
  const a = array1[i];
  const b = array2[i];
  const c = array3[i];
  
  // check all preceding columns for equality
  for (let j = 0; j < i; j++) {
    if (a === array1[j] && b === array2[j] && c === array3[j]) {
      // duplicate; continue at top of outer loop
      continue outer;
    }
  }

  // not a duplicate; add to new arrays
  newArray1.push(a);
  newArray2.push(b);
  newArray3.push(c);
}

console.log(newArray1);
console.log(newArray2);
console.log(newArray3);
.as-console-wrapper{min-height:100%}

如您所见,我们必须每次检查每列中的每一行是否相等。如果你很好奇,那么它的复杂性是((+1)/ 2)(技术上((+ 1)/ 2),其中三列为3)。

对于更大的数据集,跟踪您在快速访问的数据结构中已经看到的值是有利的:哈希,a.k.a.JavaScript对象。由于您的所有值都是原始值,因此构造键的快速方法是JSON.stringify。有些人可能认为这是“黑客” - 重要的是要注意它将失败,其值不能用JSON表示,例如InfinityNaN - 但这是一个简单快捷的数据。

const array1 = ['A', 'B', 'A', 'B'];
const array2 = [5, 5, 7, 5];
const array3 = [true, true, true, true];

const newArray1 = [];
const newArray2 = [];
const newArray3 = [];

const index = {};

for (let i = 0; i < array1.length; i++) {
  const a = array1[i];
  const b = array2[i];
  const c = array3[i];
  const key = JSON.stringify([a,b,c]);
  
  if (key in index) {
    // duplicate; skip to top of loop
    continue;
  }
  
  // not a duplicate; record in index and add to new arrays
  index[key] = true;
  newArray1.push(a);
  newArray2.push(b);
  newArray3.push(c);
}

console.log(newArray1);
console.log(newArray2);
console.log(newArray3);
.as-console-wrapper{min-height:100%}

这的复杂性是(),或者可能是(2)再次,  三列是3,而另一个是非常粗略地考虑JSON.stringify的成本。 (弄清楚哈希访问的成本留给我们中的学生练习;我满足于称之为(1)。)

这仍然非常冗长。部分原因是对数据使用三个不同的变量 - 这实际上是一个单独的“表” - 导致大量重复。我们可以预处理数据,以便更容易处理。一旦它“转换”成一个二维数组,我们可以使用Array.prototype.filter和上面的关键技术,对于一些非常简洁的代码:

const array1 = ['A', 'B', 'A', 'B'];
const array2 = [5, 5, 7, 5];
const array3 = [true, true, true, true];

// turn "columns" into "rows" of a 2D array
const records = array1.map((a, i) => [a, array2[i], array3[i]]);

const index = {};
const newData = records.filter(column => {
  const key = JSON.stringify(column);
  return key in index ? false : index[key] = true;
});

console.log(newData);
.as-console-wrapper{min-height:100%}

当然,预处理不是免费的,所以这个代码不比更详细的版本更高效;你必须决定对你有多重要。如果您愿意,现在可以将newData中的列提取为三个变量(newData.forEach(([a,b,c]) => { newArray1.push(a); newArray2.push(b); /* ... */ })),但出于多种目的,“转置”2D数组将更易于使用。

答案 1 :(得分:2)

您可以使用ES6设置https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set

设置 - &gt;允许您存储任何类型的唯一值,无论是原始值还是对象引用。

然后转换回数组

检查此代码段

const array1 = ['A','B','A','B']
const array2 = [5,5,7,5]
const array3 = [true,true,true,true]

const uniqA1= new Set(array1)
const uniqA2= new Set(array2)
const uniqA3= new Set(array3)

console.log(Array.from(uniqA1))
console.log(Array.from(uniqA2))
console.log(Array.from(uniqA3))

希望有所帮助

答案 2 :(得分:1)

您需要在所有数组中找到具有相同索引的重复元素,然后过滤掉这些元素。

&#13;
&#13;
echo
&#13;
&#13;
&#13;

答案 3 :(得分:1)

你需要一些辅助函数(lodash也提供它们):

let zip = (...arys) => arys[0].map((_, i) => arys.map(a => a[i]));
let uniq = (ary, key) => uniq2(ary, ary.map(key), new Set);
let uniq2 = (ary, keys, set) => ary.filter((_, i) => !set.has(keys[i]) && set.add(keys[i]))

// test

var array1 = ['A', 'B', 'A', 'B'];
var array2 = [5, 5, 7, 5];
var array3 = [true, true, true, true];

var [x, y, z] = zip(
    ...uniq(
        zip(array1, array2, array3),
        JSON.stringify
    )
);

console.log(x, y, z)

答案 4 :(得分:0)

另一种方式,filter()

&#13;
&#13;
array1 = ['A', 'B', 'A', 'B'];
array2 = [5, 5, 7, 5];
array3 = [true, true, true, true];

uniqueArray1 = array1.filter(function(item, pos) {
  return array1.indexOf(item) == pos;
})

uniqueArray2 = array2.filter(function(item, pos) {
  return array2.indexOf(item) == pos;
})

uniqueArray3 = array3.filter(function(item, pos) {
  return array3.indexOf(item) == pos;
})

console.log(uniqueArray1);
console.log(uniqueArray2);
console.log(uniqueArray3);
&#13;
&#13;
&#13;

答案 5 :(得分:0)

这是一个很好的方法,已经回答了here

var arr = ["apple", "bannana", "orange", "apple", "orange"];

arr = arr.filter( function( item, index, inputArray ) {
           return inputArray.indexOf(item) == index;
    });


---------------------
Output: ["apple", "bannana", "orange"]

答案 6 :(得分:0)

我能想到的一种方法是使用一个对象来跟踪,这也会巧合地删除任何重复项,因为键必须是唯一的。唯一的问题是我现在可以想到如何将它提取回数组。我明天会考虑的。

这利用jquery进行深度克隆。如果你只想在vanilla javascript中使用它,你可能只需要实现深度克隆功能。

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
; (INPUT)
; data = 1-D array of intensities
; (OUTPUT)
; bck,sig = background and fluctuations (1 sig level)
; ndata = number of values upon which bck,sig are computed
; POSITIVE = retains only data values > 0
; NSIG = number of sigmas

  if not(keyword_set(NSIG)) then nsig=3.    
  if keyword_set(POSITIVE) then begin
    test=where(data gt 0.)
    if test(0) ne -1 then data2=data(test) else begin
      bck=0 & sig=-1 & ndata=0 & goto,out
    endelse
  endif else data2=data
  if n_elements(data2) gt 1 then begin
    bck=mean(data2,/double) & sig=stddev(data2,/double)
  endif else begin
    bck=data2(0) & sig=0 & ndata=1 & goto,out
  endelse
  ndata=1

loop:
  test=where(abs(data2-bck) lt nsig*sig)
  if n_elements(test) eq 1 then goto,out
  ndata=n_elements(test)
  moy=mean(data2(test),/double)
  sig=stddev(data2(test),/double)
  if moy eq bck then goto,out
  bck=moy
  goto,loop

out:
  return
end