dtd
dtd

Reputation: 89

Javascript move objects in a nested array

I have an array that is defined like this:

const arr = [
  {
    status: 'status1',
    count: 2,
    elements: [
      {
        id: '1',
      },
      {
        id: '2',
      },
    ],
  },
  {
    status: 'status2',
    count: 1,
    elements: [
      {
        id: '3',
      },
    ],
  },
  {
    status: 'status3',
    count: 1,
    elements: [
      {
        id: '4',
      },
    ],
  },
];

The array is dynamic, but I know the status field and the id inside the elements. What I am trying to achieve is a new array, that contains all the same items, but looks like this instead:

const arr = [
  {
    status: 'status1',
    count: 1,
    elements: [
      {
        id: '1',
      },
    ],
  },
  {
    status: 'status2',
    count: 2,
    elements: [
      {
        id: '2',
      },
      {
        id: '3',
      },
    ],
  },
  {
    status: 'status3',
    count: 1,
    elements: [
      {
        id: '4',
      },
    ],
  },
];

In other words, if status === status1, remove element with id === 2, set count to the length of elements array (or decrease by 1), take the element that has id === 2 and put it into elements array that has status === status2, set total count to the length of elements array .

I am not all that strong with iterating through nested elements and manipulating the array in these ways, but simpler concepts with array.filter/map etc seems okay, but I cannot wrap my head around all of this. :P

I would prefer to use vanilla JS, if possible. But I do have access to lodash if it makes things a lot easier.


Edit: When I mean vanilla JS, I refer to not using a ton of external libraries, but ES6 is what I use at this project.

My try consists of simply trying to filter arr on status, and then again on my id. Then I know what item I want to move. But it kind of stops there, and I also believe that it could be much more efficient:

const itemToMove = arr.filter(e => e.status === "status1")[0].elements.filter(e => e.id ==='2' )

I am not sure how to best proceed after this, thus asking for help.

Upvotes: 1

Views: 935

Answers (1)

Nina Scholz
Nina Scholz

Reputation: 386520

You could find the source and target objects and splice the element.

const
    move = (data, from, to, id) => {
        const
            find = value => ({ status }) => status === value,
            source = data.find(find(from)),
            target = data.find(find(to)),
            index = source.elements.findIndex(o => o.id === id);
            
        if (index === -1) return;
        
        target.elements.push(...source.elements.splice(index, 1));
        source.count--;
        target.count++;
    },
    array = [{ status: 'status1', count: 2, elements: [{ id: '1' }, { id: '2' }] }, { status: 'status2', count: 1, elements: [{ id: '3' }] }, { status: 'status3', count: 1, elements: [{ id: '4' }] }];
   

move(array, 'status1', 'status2', '2');
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 2

Related Questions