使用"reduce"操作对象并生成数组



我知道reduce在Javascript中是一个非常强大的数组方法,并且已经看到了很多例子,但不能用它来完成下面的任务。

按年龄分组统计对象,年龄差异不得超过5,每组最多只能有3人。

我已经能够使用以下代码实现它

const immutable = require('../fixtures/inputs/input')
const edge = require('../fixtures/inputs/edge-input')
/**
* This is the entry point to the program
*
* @param {any} input Array of student objects
*/

function classifier(input) {
// console.log(input)
// let returnedInput = []
let newInput = JSON.parse(JSON.stringify(input));
let exampleOutput = {
}

if (!Array.isArray(newInput)) {
throw new Error("invalid")
}
if (newInput.length < 1) {
exampleOutput = { noOfGroups: 0 }
}
function compare(a, b) {
const { age: ageA, regNo: regNoA } = a
const { age: ageB, regNo: regNoB } = b
// const ageA = a.age
// const ageB = b.age
let comparison = 0;
if (ageA > ageB) {
comparison = 1;
} else if (ageA < ageB) {
comparison = -1;
}
return comparison
}
const ages = newInput.map(function (each) {
let datDob = new Date(each.dob).getFullYear()
return each.age = new Date().getFullYear() - datDob
})
sortedInput = newInput.sort(compare)
// console.log(sortedInput)
const getMember = (arg) => {
let memArray = []
// console.log(arg)
if (arg.length == 1) {
return arg
}
let i = 0;
let j = 1;
// console.log(arg)
// console.log(arg.length)
while (i <= arg.length) {
while (j < 3) {
//  console.log(arg[j])
if (arg[j]) {
if ((arg[j].age - arg[i].age) <= 5) {
memArray.push(arg[j])
}
}
j++
}
memArray.push(arg[i])
i++
return memArray
}
}
let i = 0;
// console.log(sortedInput)
while (sortedInput.length >= 1) {
// console.log(sortedInput)
let memberss = getMember(sortedInput)
memberss = memberss.sort(compare)
// let memRegSort = memberss.sort((a, b) => (a.regNo > b.regNo) ? 1 : -1) 
memberss = memberss.sort((a, b) => (a.age > b.age) ? 1 : (a.age === b.age) ? ((a.regNo > b.regNo) ? 1 : -1) : -1)
// return memberss
const oldest = memberss.map(item => item.age).reduce((a, b) => Math.max(a, b))
const sumAge = memberss.map(item => item.age).reduce((total, curVal) => total + curVal)
const regNo = memberss.map(item => parseInt(item.regNo))
exampleOutput[`noOfGroups`] = i + 1
exampleOutput[`group${i + 1}`] = {}
exampleOutput[`group${i + 1}`]['members'] = memberss
exampleOutput[`group${i + 1}`].oldest = oldest
exampleOutput[`group${i + 1}`].sum = sumAge
exampleOutput[`group${i + 1}`].regNos = regNo.sort((a, b) => a > b ? 1 : -1)
sortedInput = sortedInput.slice(memberss.length, sortedInput.length + 1)
// console.log(sortedInput)
// sortedInput.splice(0, memberss.length)
// console.log(exampleOutput[`group${i + 1}`]['members'])

i++
}
// console.log(exampleOutput)
return exampleOutput
// console.log (getMember(sortedInput))
}
const input = [
{
name: 'Hendrick',
dob: '1853-07-18T00:00:00.000Z',
regNo: '041',
}
]
Object.freeze(edge)
const out = classifier(edge)
console.log(out)
module.exports = classifier;

输入

const input = [
{
name: 'Hendrick',
dob: '1853-07-18T00:00:00.000Z',
regNo: '041',
},
{
name: 'Albert',
dob: '1910-03-14T00:00:00.000Z',
regNo: '033',
},
{
name: 'Marie',
dob: '1953-11-07T00:00:00.000Z',
regNo: '024',
},
{
name: 'Neils',
dob: '1853-10-07T00:00:00.000Z',
regNo: '02',
},
{
name: 'Max',
dob: '1853-04-23T00:00:00.000Z',
regNo: '014',
},
{
name: 'Erwin',
dob: '1854-08-12T00:00:00.000Z',
regNo: '09',
},
{
name: 'Auguste',
dob: '1854-01-28T00:00:00.000Z',
regNo: '08',
},
{
name: 'Karl',
dob: '1852-12-05T00:00:00.000Z',
regNo: '120',
},
{
name: 'Louis', //
dob: '1852-08-15T00:00:00.000Z',
regNo: '022',
},
{
name: 'Arthur',
dob: '1892-09-10T00:00:00.000Z',
regNo: '321',
},
{
name: 'Paul',
dob: '1902-08-08T00:00:00.000Z',
regNo: '055',
},
{
name: 'William',
dob: '1890-03-31T00:00:00.000Z',
regNo: '013',
},
{
name: 'Owen',
dob: '1853-04-26T00:00:00.000Z',
regNo: '052',
},
{
name: 'Martin',
dob: '1854-02-15T00:00:00.000Z',
regNo: '063',
},
{
name: 'Guye',
dob: '1854-10-15T00:00:00.000Z',
regNo: '084',
},
{
name: 'Charles',
dob: '1954-02-14T00:00:00.000Z',
regNo: '091',
},
];
module.exports = input;

输出

{ noOfGroups: 8,
group1:
{ members:
'[{"name":"Charles","dob":"1954-02-14T00:00:00.000Z","regNo":"091","age":65},{"name":"Marie","dob":"1953-11-07T00:00:00.000Z","regNo":"024","age":66}]',
oldest: 66,
sum: 131,
regNos: [ 24, 91 ] },
group2:
{ members:
'[{"name":"Albert","dob":"1910-03-14T00:00:00.000Z","regNo":"033","age":109}]',     oldest: 109,
sum: 109,
regNos: [ 33 ] },
group3:
{ members:
'[{"name":"Paul","dob":"1902-08-08T00:00:00.000Z","regNo":"055","age":117}]',  
oldest: 117,
sum: 117,
regNos: [ 55 ] },
group4:
{ members:
'[{"name":"Arthur","dob":"1892-09-10T00:00:00.000Z","regNo":"321","age":127},{"name":"William","dob":"1890-03-31T00:00:00.000Z","regNo":"013","age":129}]',
oldest: 129,
sum: 256,
regNos: [ 13, 321 ] },
group5:
{ members:
'[{"name":"Auguste","dob":"1854-01-28T00:00:00.000Z","regNo":"08","age":165},{"name":"Guye","dob":"1854-10-15T00:00:00.000Z","regNo":"084","age":165},{"name":"Erwin","dob":"1854-08-12T00:00:00.000Z","regNo":"09","age":165}]',
oldest: 165,
sum: 495,
regNos: [ 8, 9, 84 ] },
group6:
{ members:
'[{"name":"Martin","dob":"1854-02-15T00:00:00.000Z","regNo":"063","age":165},{"name":"Max","dob":"1853-04-23T00:00:00.000Z","regNo":"014","age":166},{"name":"Hendrick","dob":"1853-07-18T00:00:00.000Z","regNo":"041","age":166}]',
oldest: 166,
sum: 497,
regNos: [ 14, 41, 63 ] },
group7:
{ members:
'[{"name":"Neils","dob":"1853-10-07T00:00:00.000Z","regNo":"02","age":166},{"name":"Owen","dob":"1853-04-26T00:00:00.000Z","regNo":"052","age":166},{"name":"Karl","dob":"1852-12-05T00:00:00.000Z","regNo":"120","age":167}]',
oldest: 167,
sum: 499,
regNos: [ 2, 52, 120 ] },
group8:
{ members:
'[{"name":"Louis","dob":"1852-08-15T00:00:00.000Z","regNo":"022","age":167}]', 
oldest: 167,
sum: 167,
regNos: [ 22 ] } }

我如何使用减少完成相同的工作。 我已经尝试了下面的代码

function classifier(input) {
let newInput = JSON.parse(JSON.stringify(input));
let exampleOutput = {
noOfGroups:0,
group: {
member: [],
oldest: 0,
regNos: []
}
}
if (!Array.isArray(newInput)) {
throw new Error("invalid")
}
if (newInput.length < 1) {
exampleOutput = { noOfGroups: 0 }
}
function compare(a, b) {
const { age: ageA } = a
const { age: ageB } = b
return ageA-ageB
}
const ages = newInput.map(function (each) {
let datDob = new Date(each.dob).getFullYear()
return each.age = new Date().getFullYear() - datDob
})
sortedInput = newInput.sort(compare)

const member = (arr)=>{
let result = []
return arr.length < 1 ? { noOfGroups: 0} : 
arr.reduce((acc, cur, index, arr) => {
index= index-1
let num = 0
// console.log(cur.age)
let item = arr.findIndex(item => item.age +5 >= cur.age)
item == 0 ? result.push(cur) : result

result.length > 3 ? result.pop() : result
num = num+1
acc.noOfGroups = num
acc[`group${num}`] = {}
acc[`group${num}`].members = []
acc[`group${num}`].members.push(result)
acc[`group${num}`].oldest = result.map(item => item.age).reduce((a, b) => Math.max(a, b))
acc[`group${num}`].regNos = result.map(item => item.age)
// console.log(arr.slice)
index = index-1
return index < 0 ? member(arr.slice(acc[`group${num}`].regNos.length, 16)) : acc

return acc

}, [{noOfGroups: 0}, ])
}

return member(sortedInput)
return exampleOutput

}

但是得到了一组的输出,如下所示:

{ noOfGroups: 1,
group1: { members: [ [Array] ], oldest: 66, regNos: [ 65, 66 ] } }

这是我的做法:

  1. 首先从每个人的dob中计算age
  2. 然后使用 reduce(( 转换数据。如果存在满足给定条件的组,则我们将当前成员添加到该组中并重新计算sumoldest和其他属性。如果没有,我们将创建一个包含当前成员的新组。

const input = [ { name: 'Hendrick', dob: '1853-07-18T00:00:00.000Z', regNo: '041', }, { name: 'Albert', dob: '1910-03-14T00:00:00.000Z', regNo: '033', }, { name: 'Marie', dob: '1953-11-07T00:00:00.000Z', regNo: '024', }, { name: 'Neils', dob: '1853-10-07T00:00:00.000Z', regNo: '02', }, { name: 'Max', dob: '1853-04-23T00:00:00.000Z', regNo: '014', }, { name: 'Erwin', dob: '1854-08-12T00:00:00.000Z', regNo: '09', }, { name: 'Auguste', dob: '1854-01-28T00:00:00.000Z', regNo: '08', }, { name: 'Karl', dob: '1852-12-05T00:00:00.000Z', regNo: '120', }, { name: 'Louis', dob: '1852-08-15T00:00:00.000Z', regNo: '022', }, { name: 'Arthur', dob: '1892-09-10T00:00:00.000Z', regNo: '321', }, { name: 'Paul', dob: '1902-08-08T00:00:00.000Z', regNo: '055', }, { name: 'William', dob: '1890-03-31T00:00:00.000Z', regNo: '013', }, { name: 'Owen', dob: '1853-04-26T00:00:00.000Z', regNo: '052', }, { name: 'Martin', dob: '1854-02-15T00:00:00.000Z', regNo: '063', }, { name: 'Guye', dob: '1854-10-15T00:00:00.000Z', regNo: '084', }, { name: 'Charles', dob: '1954-02-14T00:00:00.000Z', regNo: '091', }, ];
// Compute age from DOB.
const data = input.map(item => {
let age = new Date().getFullYear() - new Date(item.dob).getFullYear();
return {...item, age};
});
var result = data.reduce((acc, curr) => {
let group = Object.values(acc).find(group => group.members && group.members.length < 3 
&& group.members.every(member => Math.abs(member.age - curr.age) < 5));
if (group) {
group.members.push(curr);
group.regNos.push(curr.regNo);
group.oldest = Math.max(...group.members.map(member => member.age));
group.sum = group.sum + curr.age; 
} else {
acc.noOfGroups = acc.noOfGroups + 1 || 1;
let groupName = "group" + acc.noOfGroups;
acc[groupName] = {
"members": [curr],
"oldest": curr.age,
"sum": curr.age,
"regNos": [curr.regNo],
};
}
return acc;
}, {});
console.log(result);

我首先使用 Ramda 写了这篇文章(免责声明:我是它的作者之一。 这是代码:

const transform = pipe (
map (addAge),
sortBy (prop ('age')),
makeGroups (doesItFit),
nameGroups,
map (constructGroup)
)

加上附加的辅助函数,addAgemakeGroupsdoesItFitnameGroupsconstructObj)。 我真的很喜欢这种逐步转换输出的风格。

但是Ramda只是辅助函数的集合(旨在允许某种特定的编码风格,当然(,我们自己编写这些版本很容易。

但是把这样的功能

const pipe = (...fns) => (arg) => 
fns.reduce((o, f) => f(o), arg)

在我们自己的实用程序库中,我们可以相对容易地构建像上面一样干净的代码。

对于这种情况,我最终使用了许多Ramda函数,以及可能属于此类库的两个助手(numericSortmakeGroups(。 但是这些很容易为自己编写,我们可以在它们之上构建这个函数。

// Utility functions
const pipe = (...fns) => (arg) => 
fns.reduce((o, f) => f(o), arg)
const map = (fn) => (xs) => 
xs .map (x => fn(x))
const sort = (comparator) => (xs) => 
xs .sort (comparator)
const numericSort = sort ((a, b) => a - b)
const sortBy = (fn) => (xs) => 
xs .sort ((a, b, x = fn(a), y = fn(b)) => x < y ? -1 : x > y ? 1 : 0)
const sum = (xs) =>
xs.reduce((a, b) => a + b, 0)
const prop = (name) => (obj) =>
obj [name]
const pluck = (prop) => (xs) =>
xs .map (x => x[prop])
const mapObject = (fn) => (obj) => 
Object.assign(...Object.entries(obj).map(([k, v]) => ({[k]: fn(v)})))
const makeGroups = (test) => (xs) =>
xs.reduce((groups, x) => {
const idx = groups.findIndex(g => test (g, x))
return idx > -1 
? [...groups.slice(0, idx), [...groups[idx], x], ...groups.slice(idx + 1)]
: [...groups, [x]]
}, [])
// Helpers
const addAge = ({dob, ...rest}) =>  
({...rest, dob, age: new Date().getFullYear() - new Date(dob).getFullYear()})
const nameGroups = groups =>
groups .reduce ((i => (a, g) => ({...a, [`group${i++}`]: g}))(1), {})
const doesItFit = (group, item) =>
group.length < 3 && group.every(x => Math.abs(x.age - item.age) < 5)
const constructGroup = (group) => ({
members: group,
// members: JSON.stringify(group),
oldest: Math.max(...pluck ('age') (group)),
sum: sum (pluck ('age') (group)),
regNos: numericSort (map(Number) (pluck('regNo') (group))),
})
// Main function
const transform = pipe (
map (addAge),
sortBy (prop ('age')),
makeGroups (doesItFit),
nameGroups,
mapObject (constructGroup)
)
// Demonstration
const input = [{name: "Hendrick", dob: "1853-07-18T00:00:00.000Z", regNo: "041"}, {name: "Albert", dob: "1910-03-14T00:00:00.000Z", regNo: "033"}, {name: "Marie", dob: "1953-11-07T00:00:00.000Z", regNo: "024"}, {name: "Neils", dob: "1853-10-07T00:00:00.000Z", regNo: "02"}, {name: "Max", dob: "1853-04-23T00:00:00.000Z", regNo: "014"}, {name: "Erwin", dob: "1854-08-12T00:00:00.000Z", regNo: "09"}, {name: "Auguste", dob: "1854-01-28T00:00:00.000Z", regNo: "08"}, {name: "Karl", dob: "1852-12-05T00:00:00.000Z", regNo: "120"}, {name: "Louis", dob: "1852-08-15T00:00:00.000Z", regNo: "022"}, {name: "Arthur", dob: "1892-09-10T00:00:00.000Z", regNo: "321"}, {name: "Paul", dob: "1902-08-08T00:00:00.000Z", regNo: "055"}, {name: "William", dob: "1890-03-31T00:00:00.000Z", regNo: "013"}, {name: "Owen", dob: "1853-04-26T00:00:00.000Z", regNo: "052"}, {name: "Martin", dob: "1854-02-15T00:00:00.000Z", regNo: "063"}, {name: "Guye", dob: "1854-10-15T00:00:00.000Z", regNo: "084"}, {name: "Charles", dob: "1954-02-14T00:00:00.000Z", regNo: "091"}];
console .log (
transform (input)
)

这不会在输出中列出 JSON 样式的成员。 我发现该输出很奇怪,但是如果您想要它,只需替换

即可
members: group,

members: JSON.stringify(group),

constructGroup.


您询问了reduce的使用。 虽然在这个例子中它有几种用途,但关键的是函数makeGroups。 (这个函数可能应该添加到Ramda中。 它的效率不是很高,性能O (n^2)最差,但我不知道有什么比这更有效的了。 这显然很有用。

makeGroups采用二进制谓词和项目列表,并通过为每个项目查找谓词应用于组和项目时返回 true 的第一组,并将项目添加到该组,返回对它们进行分组的结果。 如果未找到任何内容,它将启动一个仅包含该项目的新组。 谓词必须采用组和项,并报告该项是否属于该组。 在当前情况下,我们提供的谓词是doesItFit,它检查该组的长度是否小于 3,并且项目的年龄是否在组中所有项目的 5 以内。

最新更新