从阵列中获取唯一值的最快方法是什么?

时间:2018-03-14 03:46:39

标签: javascript node.js algorithm time-complexity

我有一个像这样的数组

students = [{name: 'Abbey', age: 25}, {name: 'Brian', age: 45},
            {name: 'Colin', age: 25}, {name: 'Dan', age: 78}]

我希望输出为;

uniqueAges = [45, 78]

要明确的是,如果学生数组中出现多次出现的年龄值,我不希望在uniqueAges数组中任何具有该年龄的对象。 'Abbey'和'Colin'的年龄相同,所以他们

我知道我可以做这样的事情并运行uniqueAgeGetter(students)

   function uniqueAgeGetter(list){
   var listCopy = list.slice();
   var uniqueAges = list.slice();
   for (var i = list.length - 1; i >= 0; i--) {
        for (var j = listCopy.length - 1; j >= 0; j--) {
            if(listCopy[j].name !== list[i].name && 
                listCopy[j].age == list[i].age){
                  uniqueAges.splice(i, 1)
                }   
            }
    }
   console.log(uniqueAges)
   return uniqueAges
 }

但是没有第二个循环可以做到吗?我不是时间复杂度的专家,但我试图找到这个任务是否可能是O(n)。

编辑: 我不是要问uniqueAgeGetter是否被重写以更好地阅读或使用map,reduce或filter等函数(因为我的理解是它们最终也是一个循环)。

我的问题是,uniqueAgeGetter能否以减少时间复杂度的方式进行重构?只用一个循环就可以完成吗?

谢谢。

6 个答案:

答案 0 :(得分:3)

这可以在O(n)时间内通过计算一个年龄的次数来计算,并过滤掉年龄超过一个的年龄。

由于年龄有合理的限制,我们可以使用长度等于最大可能年龄的整数数组来存储年龄计数。在下面的示例中,我将最大可能年龄设为舒适200



var students = [
  {name: 'Abbey', age: 25 }, 
  {name: 'Brian', age: 45 },
  {name: 'Colin', age: 25 }, 
  {name: 'Dan', age: 78 }
];

var studentAges = students.map(val => val.age);
var ageCounts = Array(200).fill(0);

studentAges.forEach(age => ageCounts[age] += 1);

var uniqueAges = studentAges.filter(age => ageCounts[age] == 1);

console.log(uniqueAges);




答案 1 :(得分:1)

您可以使用reduce

第一个reduce是汇总数组并使用age作为键将其转换为对象。使用年龄作为关键将更容易检查年龄是否已经存在。对象属性将具有类似[2,true]的数组值,其中第一个元素是年龄,第二个元素告诉年龄是否有重复。使用Object.values会将对象转换为数组。

第二个reduce是形成所需的输出。



let students = [{name: 'Abbey', age: 25 }, {name: 'Brian', age: 45 },{name: 'Colin', age: 25 }, {name: 'Dan', age: 78 }];

let uniqueAges = Object.values(students.reduce((c, v) => {
  if (c[v.age] === undefined) c[v.age] = [v.age, true];
  else c[v.age][1] = false;
  return c;
}, {})).reduce((c, v) => {
  if (v[1]) c.push(v[0]);
  return c;
}, []);

console.log(uniqueAges);




答案 2 :(得分:1)

  • 第一个想法,我们可以做两步:

    第1步:对数组进行排序

    - 有很多算法可以做到。据我所知,目前,最佳算法的复杂性现在是O(Nlog(N)),其中N是数组的数量。

    第2步:删除重复的元素

    - 这一步的复杂性是O(N) 因此,通过两个步骤,复杂度是O(N)+ O(Nlog(N))。最后,复杂性是O(Nlog(N))

  • 第二个想法

    复杂性也是O(Nlog(N)),但下次想要获得独特年龄时,它将是O(N)。

    您可以使用一点自定义在二叉搜索树中重建,而不是将数据保存在数组中。此树中的此节点将保存所有具有相同年龄的元素。

    第一次构建树时的复杂性是O(Nlog(N))

关于复杂度为O(N)的算法,目前我认为没有技术可以解决它。 :d

答案 3 :(得分:0)

这是你可以做到的一种方式。我认为时间复杂度为n,其中m是原始数组中元素的数量,const students = [ {name: 'Abbey', age: 25 }, {name: 'Brian', age: 45 }, {name: 'Colin', age: 25 }, {name: 'Dan', age: 78 } ]; const uniqueStudents = students.map(val => val.age) .sort() .reduce((current, next) => { return current.length === 0 ? [].concat(current, next) : current[current.length - 1] !== next ? [].concat(current, next) : current.slice(0, -1); }, []); console.log(uniqueStudents);是输出数组中唯一元素的数量。



notifyAll()




答案 4 :(得分:0)

您可以先使用map()获取所有年龄段,然后使用uniqueAgesreduce()获得预期的filter()



var students = [{name: 'Abbey', age: 25 }, {name: 'Brian', age: 45 }, 
{name: 'Colin', age: 25 }, {name: 'Dan', age: 78 }]

var uniqueAges = students
  .map(s => s.age)
  .reduce(function(acc, item, index, arr){
    var ageOccurrences = arr.filter(i => i == item);
    if(ageOccurrences.length === 1)
      acc.push(item)
    return acc;
  },[]);

console.log(uniqueAges);




答案 5 :(得分:0)

单次迭代的最快方法。



const students = [
  {name: `Abbey`, age: 25}, 
  {name: `Brian`, age: 45},
  {name: `Colin`, age: 25}, 
  {name: `Dan`, age: 78},
  {name: `Dan`, age: 25}
]

// no global variables
function unique(key) {
  const occurrences = {}
  const list = {}
  return (result, next, index, {length}) => {
    const value = next[key]
    if (list[value]) {
      occurrences[value] = value
    }
    else {
      list[value] = value
      result.push(value)
    }
    return index === length - 1 ? result.filter(v => !occurrences[v]) : result
  }
}

const uniqueNames = students.reduce(unique(`name`), [])
const uniqueAges = students.reduce(unique(`age`), [])

console.log(uniqueAges)