Reputation: 1056
I need to transfrm an array into another array but can't find a good way to do this. An error message tells me I can't push into found[0].children
, but I feel like all the way I'm doing it wrong and dirty; would you tell me how you manage this kind of issue?
I would like to transform the array:
const input =
[
{value: "29-08-2020 16:00", visible: 0},
{value: "29-08-2020 16:30", visible: 1},
{value: "29-08-2020 17:00", visible: 0},
{value: "30-08-2020 15:00", visible: 1},
{value: "30-08-2020 15:30", visible: 1}
];
Into the array:
const output =
[
{
id: '29/08/2020',
label: '29/08/2020',
children:
[
{
id: '16:00',
label: '16:00',
isDisabled: true
},
{
id: '16:30',
label: '16:30'
},
{
id: '17:00',
label: '17:00',
isDisabled: true
}
],
},
{
id: '30/08/2020',
label: '30/08/2020',
children:
[
{
id: '15:00',
label: '15:00'
},
{
id: '15:30',
label: '15:30'
}
]
}
];
Here is what I tried, but I am not satisfied at all with this idea, which doesn't seem like the good way...
function dateoptions(dateslist) {
var options: any[] = [];
dateslist.forEach(element => {
var tab = element.value.split(' ');
var dt = tab[0];
var time = tab[1];
var found = options.filter(opt=> opt.id==dt);
if (found.length>0) {
// I can't do this:
found[0].children.push({
'id': time,
'label': time,
disabled: element.visible==0
});
}
else {
options.push({
'id': dt,
'label': dt,
'children': {'id':time, 'label': time, disabled: element.visible==0}
});
}
});
return options;
}
Upvotes: 3
Views: 83
Reputation: 14175
The following solution is supported even in Internet Explorer 6.
var input =
[
{value: "29-08-2020 16:00", visible: 0},
{value: "29-08-2020 16:30", visible: 1},
{value: "29-08-2020 17:00", visible: 0},
{value: "30-08-2020 15:00", visible: 1},
{value: "30-08-2020 15:30", visible: 1}
];
function dateTransform(datelist)
{
var ret = [],
dateObjects = {},
i;
for(i in datelist)
{
var obj = datelist[i],
ar = obj.value.split(' '),
date = ar[0].split('-').join('/'),
child = {id: ar[1], label: ar[1]};
if(!dateObjects[date])
dateObjects[date] = {id: date, label: date, children: []};
if(!obj.visible)
child.isDisabled = !0;
dateObjects[date].children.push(child)
}
for(i in dateObjects)
ret.push(dateObjects[i]);
return ret
}
//JSON.stringify is supported first in Internet Explorer 8 version
console.log(JSON.stringify(dateTransform(input), 0, '\t'));
Upvotes: 1
Reputation: 29052
Your general idea is good, I'd use a map1 for simplicity of the lookup and create an empty entry (with empty children array) when not found:
function dateoptions (datelist) {
const dateObjects = new Map()
for (const { value, visible } of datelist) {
const [date, time] = value.split(' ')
if (!dateObjects.has(date)) {
dateObjects.set(date, {
id: date,
label: date,
children: []
})
}
dateObjects.get(date).children.push({
id: time,
label: time,
...!visible ? { isDisabled: true } : {}
})
}
return Array.from(dateObjects.values())
}
1: Why not an object? Because the iteration order of object values is not defined, even though practically all current browsers use insertion order. For a map it is defined.
Upvotes: 2
Reputation: 386736
You could reduce the array and iterate the result set for a same group.
const
data = [{ value: "29-08-2020 16:00", visible: 0 }, { value: "29-08-2020 16:30", visible: 1 }, { value: "29-08-2020 17:00", visible: 0 }, { value: "30-08-2020 15:00", visible: 1 }, { value: "30-08-2020 15:30", visible: 1 }],
result = data.reduce((r, { value, visible }) => {
let [date, time] = value.split(' '),
temp = r.find(q => q.id === date);
if (!temp) r.push(temp = { id: date, label: date, children: [] });
temp.children.push({ id: time, label: time, ...(!visible && { isDisabled: !visible }) });
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 3