3

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;
}
4
  • can you precise the options structure to be sure please ? note : you are using forEach method but you keep returns options. it does nothing Commented Jul 1, 2020 at 8:48
  • The return is outside of the forEach Commented Jul 1, 2020 at 8:51
  • @gertrude, see my solution. Maybe you would like also to mark my answer as accepted because it is supported in all brousers. Commented Jul 2, 2020 at 13:07
  • indeed, thanks for your answer! We won't use IE but it's a good alternative :) Commented Jul 6, 2020 at 6:25

3 Answers 3

3

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; }

Sign up to request clarification or add additional context in comments.

Comments

2

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.

Comments

1

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'));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.