我有一个带有动态recipients
字段数组的HTML表单,其中每个数组项都有name
和email
字段。字段名称是使用[array_name].[item_index].[field_name]
模式唯一生成的。当我提交表单时,它将生成以下JSON:
[{
name: 'recipients.0.name',
value: 'John'
}, {
name: recipients.0.email',
value: 'john@test.com'
},{
name: 'recipients.1.name',
value: 'Sam'
}, {
name: recipients.1.email',
value: 'sam@test.com'
}]
我需要将其转换为最紧凑的形式,如下所示:
{
recipients: [{
name: 'John',
email: 'john@test.com'
}, {
name: 'Sam',
email: 'sam@test.com'
}]
}
最优雅的方法是什么?欢迎使用Lodash的示例。
编辑:仅提供字段名称。解决方案应适用于模式[array_name].[item_index].[field_name]
之后的任何名称,而不仅限于recipients.[item_index].[field_name]
。
这是我的实现,对此我不太满意:
const fields = [{
name: 'recipients.0.name',
value: 'John',
},
{
name: 'recipients.0.email',
value: 'john@test.com',
},
{
name: 'recipients.1.name',
value: 'Sam',
},
{
name: 'recipients.1.email',
value: 'sam@test.com',
},
];
const compactFieldArrays = fields.reduce((result, field) => {
const [fieldArrayName, fieldArrayItemIndex, fieldName] = field.name.split('.');
let fieldArray = result[fieldArrayName];
if (!fieldArray) {
fieldArray = [];
result[fieldArrayName] = fieldArray;
}
let fieldArrayItem = fieldArray[fieldArrayItemIndex];
if (fieldArrayItem) {
fieldArrayItem[fieldName] = field.value;
} else {
fieldArrayItem = {
[fieldName]: field.value,
};
fieldArray.push(fieldArrayItem);
}
return result;
}, {});
console.log(compactFieldArrays);
答案 0 :(得分:2)
仅使用JS:
const data = [{"name":"recipients.0.name","value":"John"},{"name":"recipients.0.email","value":"john@test.com"},{"name":"recipients.1.name","value":"Sam"},{"name":"recipients.1.email","value":"sam@test.com"}]
// `reduce` over the array
const out = data.reduce((acc, { name, value }) => {
// `split` the name on the period, and pop off the key
// and the recipient id
const arr = name.split('.');
const key = arr.pop();
const recipient = arr.pop();
// Create either a new object or update the existing
// object on the accumulator
acc[recipient] = { ...acc[recipient] || {}, [key]: value };
return acc;
}, {});
console.log(Object.values(out));
答案 1 :(得分:1)
对于您的特定用例,我认为我的是最简单的:
具有未知键的字段数目未知
const arr = [{ name: 'recipients.0.name', value: 'John'}, { name: 'recipients.0.email', value: 'john@test.com'},{ name: 'recipients.1.name', value: 'Sam'}, { name: 'recipients.1.email', value: 'sam@test.com'}, { name: 'recipients.1.phone', value: '12345'}]
let recipients = [];
arr.forEach(x => {
let arr = x.name.split(".");
let key = arr[2];
let num = arr[1];
recipients[num] = recipients[num] || {}
recipients[num][key]=x.value;
})
console.log(recipients)
已知字段数
const arr = [{ name: 'recipients.0.name', value: 'John'}, { name: 'recipients.0.email', value: 'john@test.com'},{ name: 'recipients.1.name', value: 'Sam'}, { name: 'recipients.1.email', value: 'sam@test.com'}]
let recipients = [];
arr.forEach((x, i) => {
if (i == 0 || i % 2 == 0) recipients.push({"name": x.value});
else recipients[recipients.length - 1]["email"] = x.value;
})
console.log(recipients)
答案 2 :(得分:0)
按recipient.{number}.
对项目进行分组(使用String.replace()
删除字段名称)。然后映射组,并将所有字段对转换为对象,然后将所有组对象合并在一起。
const { flow, groupBy, map, merge } = _
const fn = flow(
arr => groupBy(arr, ({ name }) => name.replace(/[^.]+$/, '')),
groups => map(groups, (g, k) => merge(...
map(g, ({ name, value }) => ({ [name.replace(k, '')]: value }))
))
)
const data = [{"name":"recipients.0.name","value":"John"},{"name":"recipients.0.email","value":"john@test.com"},{"name":"recipients.1.name","value":"Sam"},{"name":"recipients.1.email","value":"sam@test.com"}]
const result = fn(data)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
和实现相同想法的lodash/fp版本,但使用_.fromPairs()
将每个组转换为对象:
const { flow, groupBy, prop, replace, map, over, fromPairs } = _
const fn = flow(
groupBy(flow(prop('name'), replace(/[^.]+$/, ''))),
map(flow(
map(flow(
over([
flow(prop('name'), replace(/.*\.([^.]+$)/, '$1')),
prop('value')
]),
)),
fromPairs
))
)
const data = [{"name":"recipients.0.name","value":"John"},{"name":"recipients.0.email","value":"john@test.com"},{"name":"recipients.1.name","value":"Sam"},{"name":"recipients.1.email","value":"sam@test.com"}]
const result = fn(data)
console.log(result)
<script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script>