'codewars Array.diff javascript
this is my first question as I'm learning programming for few days but now and I'm stuck
Task:
Your goal in this kata is to implement a difference function, which subtracts one list from another and returns the result.
It should remove all values from list
a
, which are present in listb
keeping their order.
arrayDiff([1,2],[1]) == [2]
If a value is present inb
, all of its occurrences must be removed from the other:
arrayDiff([1,2,2,2,3],[2]) == [1,3]
My solution:
function arrayDiff(a, b) {
for (var j = 0; j < a.length; j++) {
for (var i = 0; i < b.length; i++) {
if(a[j] == b[i]) {
a.splice(j);
j--;
}
}
}
return a;
}
Looks like I'm doing something wrong and peculiar thing happens: sometimes tests turn all red, sometimes all BUT 1 test turn red, while rest is green. The one that always fails me is:
Should pass Basic tests
a
was [1,2]
, b
was [1]
: expected []
to deeply equal [ 2 ]
Solution 1:[1]
The problem with your function is, that you change the length of your a array while in a for loop, which uses the length of a. This causes certain index to be skipped.
function arrayDiff(a, b) {
for (var j = 0; j < a.length; j++) {
for (var i = 0; i < b.length; i++) {
if(a[j] == b[i]) {
// here you change the size of a.
a.splice(j);
j--;
}
}
}
return a;
}
To fix this, create a temporary array, in which you push all values from a, which are not contained in b.
function arrayDiff(a,b) {
// Temporary array, containing all values from a, which are not contained in b
let diffArray = [];
// Looping over a
for(let i = 0; i < a.length; i++) {
// Per default we say that b does not contain a
let bContainsAValue = false;
// Loop over b
for(let y = 0; y < b.length; y++) {
// If any value in b is the same as the current value from a, we set bContainsAValue to true
if(a[i] === b[y]) bContainsAValue = true;
}
// Now only if bContainsAValue is still false, meaning it does not contain the a value, we push this value into our temporary array
if(!bContainsAValue) diffArray.push(a[i]);
}
// In the end we return the temporary array
return diffArray;
}
Here is my approach, which is simpler and uses some array functions:
function arrayDiff(a, b) {
// Filter entire a array, only keep the value if b does not contain that value
return a.filter(val => !b.includes(val));
}
Solution 2:[2]
Here is an easy approach that you can take to solve the error in your code with a mix of ES6.
Since your array length changes over the loop, you can use delete array[j]
to remove the value without changing the length of the array or the index of elements. According to this answer
If you just want to make the element at index
i
no longer exist, but you don't want the indexes of the other elements to change:
This replaces the duplicate values with undefined
. Then you can remove all the undefined
elements with a single line
a.filter(Boolean)
function arrayDiff(a, b) {
for (var j = 0; j < a.length; j++) {
for (var i = 0; i < b.length; i++) {
if (a[j] == b[i]) {
delete a[j];
}
}
}
console.log(a.filter(Boolean))
return a.filter(Boolean);
}
arrayDiff([1, 2], [1])
arrayDiff([1, 2, 2, 2, 3], [2])
Here's a single liner using ES6 without any nesting or mutation
const arrayDiff = (a, b) => a.filter(item => !b.includes(item))
console.log(arrayDiff([1, 2], [1]))
console.log(arrayDiff([1, 2, 2, 2, 3], [2]))
Solution 3:[3]
You could use the builtin methods for array, and combine that with the set. Something like the following:
function diff(a, b) {
const left = a.filter(item => !b.includes(item))
const right = b.filter(item => !a.includes(item))
return Array.from(new Set([].concat(left, right)))
}
By your example
diff([1,2,2,2,3],[2]) // returns [1, 3]
diff([1,2],[1]) // returns [2]
The function should also be transitive, I.e the parameter order should not matter when calculating a difference. So flipping the parameters should return the same result.
diff([2], [1,2,2,2,3]) // returns [1, 3]
diff([1],[1,2]) // returns [2]
Solution 4:[4]
This also works:
# create a function, pass in the listNames as parameters
def array_diff(a, b):
# create an entity removeNum: the loop through b, to check if it's in list b
for removeNumber in b:
# If removeNum is in b, loop through a as well to check if it's there
while removeNumber in a:
# So, if removeNum is in list a
try:
# Try function to remove it from a... using .remove()
a.remove(removeNumber)
# except to return empty list
except ValueError:
return[]
return a
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | |
Solution 3 | |
Solution 4 | Atieno Obwanda |