0

I have this array object:

0:
  id: "123123"
  cost: 100
  quantity: 2
1:
  id: "112233"
  cost: 100
  quantity: 5
2:
  id: "112233"
  cost: 100
  quantity: 0
3:
  id: "126233"
  cost: 100
  quantity: 0

What I want is to scan the whole object array and delete the ones with 0 quantity value. How do I do this with javascript?

Ryan
  • 179
  • 1
  • 1
  • 14
  • What have you tried so far? – subashMahapatra Jun 21 '20 at 04:52
  • you could use a loop. many libs have map - reduce tricks too. Are you using any library? – Hogan Jun 21 '20 at 04:53
  • 1
    https://stackoverflow.com/questions/15287865/remove-array-element-based-on-object-property isn’t exactly the same question, but its top two answers apply. – Ry- Jun 21 '20 at 04:54
  • https://stackoverflow.com/questions/16491758/remove-objects-from-array-by-object-property/16491790#16491790 isn’t exactly the same question, but its answers apply too. – Ry- Jun 21 '20 at 04:55

7 Answers7

3

Using the function from my answer at remove objects from array by object property,

filterInPlace(array, item => item.quantity !== 0);

const filterInPlace = (array, predicate) => {
    let end = 0;

    for (let i = 0; i < array.length; i++) {
        const obj = array[i];

        if (predicate(obj)) {
            array[end++] = obj;
        }
    }

    array.length = end;
};

const arr = [
    {
        id: "123123",
        cost: 100,
        quantity: 2,
    },
    {
        id: "112233",
        cost: 100,
        quantity: 5,
    },
    {
        id: "112233",
        cost: 100,
        quantity: 0,
    },
    {
        id: "126233",
        cost: 100,
        quantity: 0,
    },
];

filterInPlace(arr, item => item.quantity !== 0);

console.log(arr);
  • This does modify the array in place. If you don’t need that, the Array#filter equivalent is probably better.

  • This is linear-time, constant space, whereas solutions based splice have a worse worst case(s). (@Hogan’s answer is also linear-time; this is the same idea as it, but with the loops merged.)

Ry-
  • 218,210
  • 55
  • 464
  • 476
  • I don't know... I think it is one loop because the exit is based on the adding the two indexes together. Two loops makes it sound like O(N^2) or O(2N) when it is still O(N) --- thanks for the hat tip. – Hogan Jun 21 '20 at 05:45
1

array.filter() creates new array with the filtered objects.

take a look at this:

const values = [
  {id: '123123', cost: 100, quantity: 2},
  {id: '112233', cost: 100, quantity: 5},
  {id: '112233', cost: 100, quantity: 0},
  {id: '126233', cost: 100, quantity: 0},
]

const filtered = values.filter((obj) => obj.quantity !== 0)

console.log(filtered)
// expected output: [ { id: '123123', cost: 100, quantity: 2 }, { id: '112233', cost: 100, quantity: 5 } ]
Amir Meimari
  • 520
  • 5
  • 20
  • He specifically says he wants to scan an array and delete not create a new array. – Hogan Jun 21 '20 at 05:09
  • 4
    @Hogan: A lot of people don’t realize there’s a difference, so the OP might not necessarily care. – Ry- Jun 21 '20 at 05:12
  • @Ry- In my experience there is an expectation that answers do what the question asks -- not something else. Considering that filter is part of the standard API I think it more likely that a programmer would know what it did and be asking the question because that did not solve the problem. Why assume the questioner made a mistake? – Hogan Jun 21 '20 at 05:17
  • 1
    @Hogan Imho it is a good thing to mention another way in answers because we try not to answer OP alone, but many users after them. Some of them might _not_ know the API capability. Another reason: this might be an x/y problem. – Modus Tollens Jun 21 '20 at 05:23
0
let data = [
 {id: "123123",
  cost: 100,
  quantity: 2},
 { id: "112233",
  cost: 100,
  quantity: 5}, 
 { id: "112233",
  cost: 100,
  quantity: 0},
 {id: "126233",
  cost: 100,
  quantity: 0} 
];

let i =0;
 while (i < data.length) {
    if (data[i].quantity === 0) {
      data.splice(i, 1);
    } else {
      ++i;
    }
  }

console.table(data);

0

I usually don't recommend mutating the input itself. But since you have this requirement, Just created this utility in order to fulfil your requirement.

let data = [
  { id: '123123', cost: 100, quantity: 2 },
  { id: '112233', cost: 100, quantity: 5 },
  { id: '112232', cost: 100, quantity: 0 },
  { id: '112234', cost: 200, quantity: 0 },
  { id: '112235', cost: 400, quantity: 1 }
]

const indexesToBeRemoved = [];
data.forEach((d, index) => {
  if(d.quantity === 0) indexesToBeRemoved.push(index)
})

const length = indexesToBeRemoved.length;
for(let i=length-1; i>=0; i--) {
  data.splice(indexesToBeRemoved[i],1)
}

console.log(data)

One another way of fulfilling your requirement.

let data = [
  { id: '123123', cost: 100, quantity: 2 },
  { id: '112233', cost: 100, quantity: 5 },
  { id: '112232', cost: 100, quantity: 0 },
  { id: '112234', cost: 100, quantity: 0 },
  { id: '112235', cost: 100, quantity: 1 }
]

let numberOfItemsToBeRemoved = 0;

data.forEach((d, index) => {
  if(d.quantity === 0) {
    data.unshift(...data.splice(index, 1))
    numberOfItemsToBeRemoved++;
  }
})

console.log("deleted items: ", data.splice(0, numberOfItemsToBeRemoved))
console.log(data)

Hope this helps.

Nithish
  • 5,393
  • 2
  • 9
  • 24
  • I don't think this works... the array changes every time you do the splice. Did you test this? – Hogan Jun 21 '20 at 05:23
  • @Hogan, Yes I have tested this and it works. Please do let me know if there's any issue with the existing one. – Nithish Jun 21 '20 at 05:28
  • It won't work -- just try a more complicated case. For example have an item to be deleted as the 2nd item and the last item. Then you will throw an exception. or try and delete something past the end of the array. – Hogan Jun 21 '20 at 05:40
  • I tried the scenario *For example have an item to be deleted as the 2nd item and the last item* and is working as expected. Please have a look [here](https://codesandbox.io/s/clever-worker-bsl5w?file=/src/index.js) – Nithish Jun 21 '20 at 05:51
0

Just iterate over the elements of the array and check for the value of quantity and delete with splice:

let arr = [
    {
        id: "123123",
        cost: 100,
        quantity: 2,
    },
    {
        id: "112233",
        cost: 100,
        quantity: 5,
    },
    {
        id: "112233",
        cost: 100,
        quantity: 0
    },
    {
        id: "126233",
        cost: 100,
        quantity: 0
    }
];
let len = arr.length;
for( let i = 0; i < len; i++) {
    if(arr[i]['quantity'] === 0){
        arr.splice(i--,1);
        len--;
    }
}
console.log(arr);

output:

[
  { id: '123123', cost: 100, quantity: 2 },
  { id: '112233', cost: 100, quantity: 5 }
]
mipsc
  • 113
  • 7
-1

If you really have an array you can't delete -- most libraries that do this functionally will create a new object. If you want to "delete" items what you really have to do is move other elements down to over write the ones you no longer want.

So I would use the following steps.

  1. Check to see if the filter item appears at all -- if it does not there is nothing to do.

  2. If it does appear then then let n be the index of the first item to filter. next is the next item out after it.

    loop (index from n to index+next < size of array)
     while next is an item to filter increase next by 1
     copy from next to index
     --> increase next by 1 and back to start of loop
    
Hogan
  • 69,564
  • 10
  • 76
  • 117
-1

first get element indexes and then delete them

arr=[{
  'id': "123123",
  cost: 100,
  quantity: 2
},
{
  id: "112233",
  cost: 100,
  quantity: 5
},
{
  id: "112233",
  cost: 100,
  quantity: 0
},
{
  id: "126233",
  cost: 100,
  quantity: 0
}
]
index=[]
arr.forEach(x => {
 if (x.quantity==0) index.push(arr.indexOf(x))
});

    i=0
index.forEach(x=>{
  arr.splice(x+i,1)
  i--
})
console.log(arr)
Sven.hig
  • 4,449
  • 2
  • 8
  • 18
  • 1
    This is working on the example by coincidence. `arr.indexOf(x)` is the wrong operation and produces -1, which splices off the last element. If you replace that with `x`, it still won’t work, because splicing an element out changes the indexes of future elements. – Ry- Jun 21 '20 at 05:16
  • 1
    you get the element indexes and then start deleting -- after the first delete they are invalid. this solution is very broken. – Hogan Jun 21 '20 at 05:25
  • I have updated the solution do you think this code will work? – Sven.hig Jun 21 '20 at 05:36
  • No. You can't have the check in another loop -- there will always be ways it will fail because the location change with ever splice. – Hogan Jun 21 '20 at 11:05
  • … yes. I do think this code will work. :D But you can also do the splices directly instead of building an array first. – Ry- Jun 21 '20 at 16:13
  • @Hogan thanks for the response but with all respect this code works perfectly!! – Sven.hig Jun 22 '20 at 01:43
  • @Ry-♦  thank you for the response, moving the splice directly won’t work with the foreach, since it doesn’t keep a copy of the array and it performs directly on the array, which means each time there is a splice the array length gets shorter and therefore the outer indexes get lost, so it becomes cumbersome if not impossible to locate the object to delete, but if you know of a way to do it with foreach I am very curious to know about it. That said although my method works good, but it works only on arrays with objects , or different primitive elements, since each object in the array – Sven.hig Jun 22 '20 at 01:44
  • has a memory reference even if the objects are the same, it won’t work on an array of the same primitive elements, there is a way to extend the approach to get around that though, but I believe the best solution is a for loop – Sven.hig Jun 22 '20 at 01:44
  • oh I understand now, you were not using a classic array but a named list. – Hogan Jun 22 '20 at 02:05