Remove array from inside array based on index in JS - javascript

I have an array which looks like:-
[[0,1], [0,2], [0,3], [1,1], [1,2]...]
I am looking to remove one of the arrays from this array based on the indexOf() but I keep getting a value of -1, which removes the last item from the array when I try the following code:-
array = [[0,1], [0,2], [0,3], [1,1], [1,2]];
console.log('Removed value', array.splice(array.indexOf([0,3]), 1));
console.log('Result', array);
would somebody be able to point me in the right direction to help solve this issue I am having?
Thank you in advance.

You can't use indexOf because when you declare [0,3] in array.splice(array.indexOf([0,3]), 1)) you're creating a new array and this new object is not inside your array (but rather another array that has the same values).
You can use findIndex instead as follows (example):
array.findIndex(x => x[0] === 0 && x[1] === 3)
this will return 2 - now you can use it to delete:
array.splice(2, 1)

If it is OK to remove every occurrence of [0,3], then consider Array.filter combined with array destructuring of the lambda arguments. It offers a slightly leaner syntax than the other solutions.
const input = [
[0,1],
[0,2],
[0,3],
[1,1],
[1,2]
];
const result = input.filter(([x,y]) => !(x==0 && y==3));
console.log('Result=', result);

To explain why your solution will not work:
Comparison operators only work for values not passed by a reference. When dealing references, comparison operators always return false, unless the two references point to the same object. (See this on MDN)
An example:
a = [0,1]
b = a
b === a //true. a and b point to the same array.
a === [0,1] //false. a points to a different array than [0,1]
b[0] = 2
a[0] //2 - b points to the same array as a
To give you a solution (borrows from here)
//Function to compare the values inside the arrays, and determine if they are equal.
//Note: does not recurse.
function arraysEqual(arr1, arr2) {
if(arr1.length !== arr2.length)
return false;
for(var i = arr1.length; i--;) {
if(arr1[i] !== arr2[i])
return false;
}
return true;
}
array = [[0,1], [0,2], [0,3], [1,1], [1,2]];
//Find the index where x has the same values as [0,3]
array.findIndex(x => arraysEqual(x, [0,3])) //2

Related

why empty slots are being replaced with undefined while cloning array using spread syntax?

I'm creating a clone array from an array that contain some empty slots. But after cloning it is being replaced with undefined. If the source array contain some empty slots then clone array should also contain same number and at exact same position empty slots. I don't get the reason. I'm using spread syntax to clone array as:
const arr = [1, "", , null, undefined, false, , 0];
console.log('arr => ', arr);
const clone = [...arr];
console.log('clone => ', clone)
Output is as below in chrome console
Using spread syntax will invoke the object's iterator if it has one. The array iterator will:
a. Let index be 0.
b. Repeat
Let len be ? LengthOfArrayLike(array).
iii. If index ≥ len, return NormalCompletion(undefined).
(...)
1. Let elementKey be ! ToString(𝔽(index)).
2. Let elementValue be ? Get(array, elementKey).
(yield elementValue)
vi. Set index to index + 1.
And the length of a sparse array is still the index of the last element plus one:
const arr = [];
arr[5] = 'a';
console.log(arr.length);
So, even with sparse arrays, spreading them will result in the new array containing values of:
arr[0]
arr[1]
arr[2]
// ...
arr[arr.length - 1]
even when the original array has empty slots in between 0 and arr.length - 1.
If you want empty slots, spreading will only work if you delete the undesirable indices afterwards - or iterate over the array manually, only assigning indices you need.
const arr = [1, "", , null, undefined, false, , 0];
console.log('arr => ', arr);
const clone = [];
for (let i = 0; i < arr.length; i++) {
if (arr.hasOwnProperty(i)) {
clone[i] = arr[i];
}
}
console.log('clone => ', clone)
But you could also consider restructuring your code to avoid sparse arrays entirely - they're not very intuitive.
Let's take a step back
let x;
console.log(x); // undefined
console.log(typeof x); // undefined
If you don't define a variable, it is un-defined.
Let's see now an empty array:
let x = [,]; // even [] would work but I thought this one is clearer for some
console.log(x[0]); // undefined
console.log(typeof x[0]); //undefined
Why is that? Simply because
If you don't define a variable, it is un-defined.
above answers already made it pretty clear why you getting undefiend.
Just to add more If you log arr[2] you will get undefined, i haven't read it anywhere but from what i know spread operator spread the values of array/obj that is why arr[2] value is undefiend

Return the biggest number in the array (array contains a string)?

I dont understand why my code is not working, when I read it logically I feel that it should work, but what it does is return 3,4,2 as opposed to the highest number of the 3 (i.e. 4)
const array2 = ['a', 3, 4, 2] // should return 4
for(items of array2){
if(items > 0) {
console.log(Math.max(items));
}
What am I doing wrong? What have I misinterpreted? Please don't give me the answer, just tell me why my logic does'nt work
in for-loop, items is just one item actually. Each time, you print the current item. it is basically the same thing with this
const array2 = ['a', 3, 4, 2] // should return 4
for(items of array2){
if (items > 0) {
console.log(items);
}
}
you can do it with this only
const array2 = ['a', 3, 4, 2] // should return 4
console.log(Math.max(...array2.map(s => +s || Number.MIN_SAFE_INTEGER)));
check out: https://stackoverflow.com/a/44208485/16806649
if it was integer-only array, this would be enough:
const array2 = [3, 4, 2] // should return 4
console.log(Math.max(...array2));
You just need to filter the array.
Below example I am using filter() method of array and then just pass that filteredarray to Math.max() function.
isNan() function returns false for valid number.
Math.max(...filteredArr) is using spred operator to pass the values.
const arr = ['a', 3, 4, 2];
const filteredArr = arr.filter(val => {
if (!isNaN(val)) return val;
})
console.log(Math.max(...filteredArr));
I don't think you need the "For(items of arr)" instead just if the length of the array is greater than 0, then console.log(Math.max(...arr) should work.
See document ion below:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max
It is returning 3,4,2 because you are taking array2, and iterating through with each individual element of the array. items is not the entire array, it is the individual element and that is why Math.max of an individual element is just getting the same value.
just you need fliter you're array then get max value, also in arrayFilters function use to removes everything only return numbers of this array
function arrayFilters(array){
const number = array.filter(element => typeof element === 'number')
return number;
}
function getMaxValue(number){
return Math.max.apply(null,number)
}
const arr = ['a',2,3,4];
console.log(getMaxValue(arrayFilters(arr)))

Array, return original index from a sorted array in javascript

'I wish to sort an array in numerical order but once it is sorted I wish to be able to find the original index.
For example the original array:
ptsGP = [3,8,2,5,6,9,8,4]
I am using the following code below to sort the array:
arr = ptsGP;
var arr2 = arr.map(function(o, i){return {idx: i, obj: o}; }).sort(function(a, b) {
return b.obj - a.obj;
});
for(var i = 1, j = arr2.length; i <= j; i++){
document.write('i:' + i + ' = arr2[i].obj: PTS: ', arr2[i-1].obj+"<br/>");
}`
This is fine as the sorted array is :
arr = [2,3,4,5,6,8,8,9];
How can I find the index of sorted number in the original array? In this case it would be :
Index on original array would be = [2,0,7,3,4,1,6,5]
I know I could use map on the original array but how can I deal with duplicate numbers i.e, in this case I have two number 8's within the array?
You can achieve it by following below steps :
Creating a deep copy of an original array by using spread operator. So that we can get proper indexing.
Now we can iterate deep copy array to get the index of the elements from an original array.
Regarding duplicate values we can check via .indexOf() and .lastIndexOf() methods.
via and then via comparison. For fetching the correct index of duplicate values I wrote a logic based on the count of duplicate value.
Working Demo :
// Original array.
const originalArray = [3, 8, 2, 5, 6, 9, 8, 4];
// Creating a deep copy of an original array.
const deepCopy = [...originalArray].sort(function(a, b){
return a-b
});
// result array
const arr = [];
// count to get the index based on duplicate values.
let count = 0;
// Iterating deepCopy array to get the actual index.
deepCopy.forEach((elem) => {
// Checking for duplicate value in an array
if (originalArray.indexOf(elem) === originalArray.lastIndexOf(elem)) {
// This line of code execute if there is no duplicates in an array.
arr.push(originalArray.indexOf(elem))
} else {
// This line of code execute if there is duplicate values in an array.
count++;
// Inserting the index one by one.
arr.push(originalArray.indexOf(elem, count))
}
});
// Result array.
console.log(arr);

Why can't I use Array#includes for a nested array?

Why does the following line return false in Javascript:
[[1,2,3], [1,2,4]].includes([1,2,3]);
What is the underlying logic behind that?
includes compares using SameValueZero equality algorithm. (As mentioned in developer.mozilla.org). When searching for objects (array is object as well), it will match only references to the same object.
Additionally, Javascript arrays are objects and you can't simply use the equality operator == to understand if the content of those objects is the same. The equality operator will only test if two object are actually exactly the same instance (e.g. myObjVariable==myObjVariable, works for null and undefined too).
Both [1,2,3] expressions create a new array object. Even though the contents are the same, the objects themselves are different.
See for example this:
const array1 = [1, 2, 3];
const array2 = [1, 2, 3];
console.log(array1 == array2); // false, different objects
const array = [1, 2, 3];
console.log(array == array); // true, same object
.includes check the equity for every value in the array. In JavaScript, two arrays with the same values are not equivalent. See this thread for more details: How to compare arrays in JavaScript?
You could do this to check if an array contains an array. I use Lodash for the equity comparison and the .some property to check if one element in the array returns true.
console.log(
[[1,2,3], [1,2,4]].some((array) => _.isEqual(array, [1,2,3]))
)
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.4/lodash.min.js"></script>
Because they are mutable. If you want to check for array, you need to check by variable.
var a = [1,2];
var b = a;
[a].includes(b);
When you check for [[1,2,]].includes([1,2,3]), it returns false, because they are treated as two different objects; i.e. [1,2] == [1,2] returns false.
However, for immutable objects, such as string and number, you can check directly, such as
["a", "b"].includes("a") //true
[1, 2].includes(1) //true
"a" == "a" // true
You can do it using only Array.some() (Array.prototype.some() more precisely) method like the followings
console.log([[1,2,3], [1,2,4]].some(e => e[0] === 1 && e[1] === 2 && e[2] === 3)); // would return 'true'
console.log([[1,2,3], [1,2,4]].some(e => e[0] === 1 && e[1] === 2 && e[2] === 4)); // would return 'true'
console.log([[1,2,3], [1,2,4]].some(e => e[0] === 1 && e[1] === 2 && e[2] === 5)); // would return 'false'

Duplicate an array an arbitrary number of times (javascript)

Let's say I'm given an array. The length of this array is 3, and has 3 elements:
var array = ['1','2','3'];
Eventually I will need to check if this array is equal to an array with the same elements, but just twice now. My new array is:
var newArray = ['1','2','3','1','2','3'];
I know I can use array.splice() to duplicate an array, but how can I duplicate it an unknown amount of times? Basically what I want is something that would have the effect of
var dupeArray = array*2;
const duplicateArr = (arr, times) =>
Array(times)
.fill([...arr])
.reduce((a, b) => a.concat(b));
This should work. It creates a new array with a size of how many times you want to duplicate it. It fills it with copies of the array. Then it uses reduce to join all the arrays into a single array.
The simplest solution is often the best one:
function replicate(arr, times) {
var al = arr.length,
rl = al*times,
res = new Array(rl);
for (var i=0; i<rl; i++)
res[i] = arr[i % al];
return res;
}
(or use nested loops such as #UsamaNorman).
However, if you want to be clever, you also can repeatedly concat the array to itself:
function replicate(arr, times) {
for (var parts = []; times > 0; times >>= 1) {
if (times & 1)
parts.push(arr);
arr = arr.concat(arr);
}
return Array.prototype.concat.apply([], parts);
}
Basic but worked for me.
var num = 2;
while(num>0){
array = array.concat(array);
num--}
Here's a fairly concise, non-recursive way of replicating an array an arbitrary number of times:
function replicateArray(array, n) {
// Create an array of size "n" with undefined values
var arrays = Array.apply(null, new Array(n));
// Replace each "undefined" with our array, resulting in an array of n copies of our array
arrays = arrays.map(function() { return array });
// Flatten our array of arrays
return [].concat.apply([], arrays);
}
console.log(replicateArray([1,2,3],4)); // output: [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
What's going on?
The first two lines use apply and map to create an array of "n" copies of your array.
The last line uses apply to flatten our recently generated array of arrays.
Seriously though, what's going on?
If you haven't used apply or map, the code might be confusing.
The first piece of magic sauce here is the use of apply() which makes it possible to either pass an array to a function as though it were a parameter list.
Apply uses three pieces of information: x.apply(y,z)
x is the function being called
y is the object that the function is being called on (if null, it uses global)
z is the parameter list
Put in terms of code, it translates to: y.x(z[0], z[1], z[2],...)
For example
var arrays = Array.apply(null, new Array(n));
is the same as writing
var arrays = Array(undefined,undefined,undefined,... /*Repeat N Times*/);
The second piece of magic is the use of map() which calls a function for each element of an array and creates a list of return values.
This uses two pieces of information: x.map(y)
x is an array
y is a function to be invoked on each element of the array
For example
var returnArray = [1,2,3].map(function(x) {return x + 1;});
would create the array [2,3,4]
In our case we passed in a function which always returns a static value (the array we want to duplicate) which means the result of this map is a list of n copies of our array.
You can do:
var array = ['1','2','3'];
function nplicate(times, array){
//Times = 2, then concat 1 time to duplicate. Times = 3, then concat 2 times for duplicate. Etc.
times = times -1;
var result = array;
while(times > 0){
result = result.concat(array);
times--;
}
return result;
}
console.log(nplicate(2,array));
You concat the same array n times.
Use concat function and some logic: http://www.w3schools.com/jsref/jsref_concat_array.asp
Keep it short and sweet
function repeat(a, n, r) {
return !n ? r : repeat(a, --n, (r||[]).concat(a));
}
console.log(repeat([1,2,3], 4)); // [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
http://jsfiddle.net/fLo3uubk/
if you are inside a loop you can verify the current loop index with the array length and then multiply it's content.
let arr = [1, 2, 3];
if(currentIndex > arr.length){
//if your using a loop, make sure to keep arr at a level that it won't reset each loop
arr.push(...arr);
}
Full Example:
https://jsfiddle.net/5k28yq0L/
I think you will have to write your own function, try this:
function dupArray(var n,var arr){
var newArr=[];
for(var j=0;j<n;j++)
for(var i=0;i<arr.length;i++){
newArr.push(arr[i]);
}
return newArr;
}
A rather crude solution for checking that it duplicates...
You could check for a variation of the length using modulus:
Then if it might be, loop over the contents and compare each value until done. If at any point it doesn't match before ending, then it either didn't repeat or stopped repeating before the end.
if (array2.length % array1.length == 0){
// It might be a dupe
for (var i in array2){
if (i != array1[array2.length % indexOf(i)]) { // Not Repeating }
}
}

Categories

Resources