我有一个像这样的数组
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能否以减少时间复杂度的方式进行重构?只用一个循环就可以完成吗?
谢谢。
答案 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()
获取所有年龄段,然后使用uniqueAges
和reduce()
获得预期的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)