I have an array that contains 12 records. When i slice 4 elements from it. I shows me the sliced value, but when i slice the same array again it doesn't work for me.
var arraySliced = [a,b,c,d,e,f,g,h,i,j,k,h]
var Array1 = this.arraySliced.slice(0,4);
var Array2 = this.arraySliced.slice(4,4);
var Array3 = this.arraySliced.slice(8,4);
Array1 getting value:- a,b,c,d, but not getting value in array 2 and 3
You are assigning an object instead of array(as your requirement), I replaced array
Seccond you are using slice function incorrectly, the actual slice function defination is,
array.slice(start, end)
Try below code snippat ,
var arraySliced = ['a','b','c','d','e','f','g','h','i','j','k','h']
var Array1 = this.arraySliced.slice(0,4);
var Array2 = this.arraySliced.slice(5,7);
var Array3 = this.arraySliced.slice(8,11);
console.log(Array1);
console.log(Array2);
console.log(Array3);
slice(start_number, end_number)
var Array2 = this.arraySliced.slice(4,4);
=> Will not give any element because it doesn't get any number as per syntax.
If you want you can arraySliced.slice(4,5); will gives output ["e"]
arraySliced.slice(8,4)
=> Start number can't be greater than end number
The following function shows you what goes on when slicing up the array.
You need to state the block size and have the function figure out the number of blocks. The rest is just doing the slicing for you.
The underflow is just a safeguard, JavaScript does not care if your end index goes out of the array bounds.
var originalArray = [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l' ];
var arraySlices = partitionArray(originalArray, 4);
console.log(arraySlices);
function partitionArray(arr, blockSize) {
var partitions = [],
numBlocks = Math.ceil(arr.length / blockSize),
underflow = numBlocks * blockSize - arr.length;
for (var index = 0; index < numBlocks; index++) {
var startIndex = index * blockSize,
endIndex = startIndex + blockSize - (index === numBlocks - 1 ? underflow : 0);
partitions.push(arr.slice(startIndex, endIndex));
}
return partitions;
}
.as-console-wrapper { top: 0; min-height: 100%; }
There are a couple of things you need to remember when using .slice().
As noted above, and in the docs: .slice(startNumber, endNumber)
Both of the parameters are optional.
REMEMBER start counting from Zero.
var Array0 = arraySliced(); // copies the entire array
var Array1 = arraySliced(0,4); // [a,b,c,d]
REMEMBER the endNumber tells JS where to stop counting BUT DOSEN'T include the endNumber element.
startNumber IS included in the resulting array.
So, your .slice(4,4), says to start counting at element index=4 (but the 5th element: e) and stop counting at the same element, but not include it, so basically this results in an empty array.
.slice(8,4) also results in the creation of an empty array.
Finally, if you want to count from the end of the array, use negative numbers:
.slice(-4); // [i,j,k,h]
Related
What is the difference between spread operator and array.concat()
let parts = ['four', 'five'];
let numbers = ['one', 'two', 'three'];
console.log([...numbers, ...parts]);
Array.concat() function
let parts = ['four', 'five'];
let numbers = ['one', 'two', 'three'];
console.log(numbers.concat(parts));
Both results are same. So, what kind of scenarios we want to use them? And which one is best for performance?
concat and spreads are very different when the argument is not an array.
When the argument is not an array, concat adds it as a whole, while ... tries to iterate it and fails if it can't. Consider:
a = [1, 2, 3]
x = 'hello';
console.log(a.concat(x)); // [ 1, 2, 3, 'hello' ]
console.log([...a, ...x]); // [ 1, 2, 3, 'h', 'e', 'l', 'l', 'o' ]
Here, concat treats the string atomically, while ... uses its default iterator, char-by-char.
Another example:
x = 99;
console.log(a.concat(x)); // [1, 2, 3, 99]
console.log([...a, ...x]); // TypeError: x is not iterable
Again, for concat the number is an atom, ... tries to iterate it and fails.
Finally:
function* gen() { yield *'abc' }
console.log(a.concat(gen())); // [ 1, 2, 3, Object [Generator] {} ]
console.log([...a, ...gen()]); // [ 1, 2, 3, 'a', 'b', 'c' ]
concat makes no attempt to iterate the generator and appends it as a whole, while ... nicely fetches all values from it.
To sum it up, when your arguments are possibly non-arrays, the choice between concat and ... depends on whether you want them to be iterated.
The above describes the default behaviour of concat, however, ES6 provides a way to override it with Symbol.isConcatSpreadable. By default, this symbol is true for arrays, and false for everything else. Setting it to true tells concat to iterate the argument, just like ... does:
str = 'hello'
console.log([1,2,3].concat(str)) // [1,2,3, 'hello']
str = new String('hello');
str[Symbol.isConcatSpreadable] = true;
console.log([1,2,3].concat(str)) // [ 1, 2, 3, 'h', 'e', 'l', 'l', 'o' ]
Performance-wise concat is faster, probably because it can benefit from array-specific optimizations, while ... has to conform to the common iteration protocol. Timings:
let big = (new Array(1e5)).fill(99);
let i, x;
console.time('concat-big');
for(i = 0; i < 1e2; i++) x = [].concat(big)
console.timeEnd('concat-big');
console.time('spread-big');
for(i = 0; i < 1e2; i++) x = [...big]
console.timeEnd('spread-big');
let a = (new Array(1e3)).fill(99);
let b = (new Array(1e3)).fill(99);
let c = (new Array(1e3)).fill(99);
let d = (new Array(1e3)).fill(99);
console.time('concat-many');
for(i = 0; i < 1e2; i++) x = [1,2,3].concat(a, b, c, d)
console.timeEnd('concat-many');
console.time('spread-many');
for(i = 0; i < 1e2; i++) x = [1,2,3, ...a, ...b, ...c, ...d]
console.timeEnd('spread-many');
Well console.log(['one', 'two', 'three', 'four', 'five']) has the same result as well, so why use either here? :P
In general you would use concat when you have two (or more) arrays from arbitrary sources, and you would use the spread syntax in the array literal if the additional elements that are always part of the array are known before. So if you would have an array literal with concat in your code, just go for spread syntax, and just use concat otherwise:
[...a, ...b] // bad :-(
a.concat(b) // good :-)
[x, y].concat(a) // bad :-(
[x, y, ...a] // good :-)
Also the two alternatives behave quite differently when dealing with non-array values.
I am replying just to the performance question since there are already good answers regarding the scenarios. I wrote a test and executed it on the most recent browsers. Below the results and the code.
/*
* Performance results.
* Browser Spread syntax concat method
* --------------------------------------------------
* Chrome 75 626.43ms 235.13ms
* Firefox 68 928.40ms 821.30ms
* Safari 12 165.44ms 152.04ms
* Edge 18 1784.72ms 703.41ms
* Opera 62 590.10ms 213.45ms
* --------------------------------------------------
*/
Below the code I wrote and used.
const array1 = [];
const array2 = [];
const mergeCount = 50;
let spreadTime = 0;
let concatTime = 0;
// Used to popolate the arrays to merge with 10.000.000 elements.
for (let i = 0; i < 10000000; ++i) {
array1.push(i);
array2.push(i);
}
// The spread syntax performance test.
for (let i = 0; i < mergeCount; ++i) {
const startTime = performance.now();
const array3 = [ ...array1, ...array2 ];
spreadTime += performance.now() - startTime;
}
// The concat performance test.
for (let i = 0; i < mergeCount; ++i) {
const startTime = performance.now();
const array3 = array1.concat(array2);
concatTime += performance.now() - startTime;
}
console.log(spreadTime / mergeCount);
console.log(concatTime / mergeCount);
The one difference I think is valid is that using spread operator for large array size will give you error of Maximum call stack size exceeded which you can avoid using the concat operator.
var someArray = new Array(600000);
var newArray = [];
var tempArray = [];
someArray.fill("foo");
try {
newArray.push(...someArray);
} catch (e) {
console.log("Using spread operator:", e.message)
}
tempArray = newArray.concat(someArray);
console.log("Using concat function:", tempArray.length)
There is one very important difference between concat and push in that the former does not mutate the underlying array, requiring you to assign the result to the same or different array:
let things = ['a', 'b', 'c'];
let moreThings = ['d', 'e'];
things.concat(moreThings);
console.log(things); // [ 'a', 'b', 'c' ]
things.push(...moreThings);
console.log(things); // [ 'a', 'b', 'c', 'd', 'e' ]
I've seen bugs caused by the assumption that concat changes the array (talking for a friend ;).
Update:
Concat is now always faster than spread. The following benchmark shows both small and large-size arrays being joined: https://jsbench.me/nyla6xchf4/1
// preparation
const a = Array.from({length: 1000}).map((_, i)=>`${i}`);
const b = Array.from({length: 2000}).map((_, i)=>`${i}`);
const aSmall = ['a', 'b', 'c', 'd'];
const bSmall = ['e', 'f', 'g', 'h', 'i'];
const c = [...a, ...b];
// vs
const c = a.concat(b);
const c = [...aSmall, ...bSmall];
// vs
const c = aSmall.concat(bSmall)
Previous:
Although some of the replies are correct when it comes to performance on big arrays, the performance is quite different when you are dealing with small arrays.
You can check the results for yourself at https://jsperf.com/spread-vs-concat-size-agnostic.
As you can see, spread is 50% faster for smaller arrays, while concat is multiple times faster on large arrays.
The answer by #georg was helpful to see the comparison. I was also curious about how .flat() would compare in the running and it was by far the worst. Don't use .flat() if speed is a priority. (Something I wasn't aware of until now)
let big = new Array(1e5).fill(99);
let i, x;
console.time("concat-big");
for (i = 0; i < 1e2; i++) x = [].concat(big);
console.timeEnd("concat-big");
console.time("spread-big");
for (i = 0; i < 1e2; i++) x = [...big];
console.timeEnd("spread-big");
console.time("flat-big");
for (i = 0; i < 1e2; i++) x = [[], big].flat();
console.timeEnd("flat-big");
let a = new Array(1e3).fill(99);
let b = new Array(1e3).fill(99);
let c = new Array(1e3).fill(99);
let d = new Array(1e3).fill(99);
console.time("concat-many");
for (i = 0; i < 1e2; i++) x = [1, 2, 3].concat(a, b, c, d);
console.timeEnd("concat-many");
console.time("spread-many");
for (i = 0; i < 1e2; i++) x = [1, 2, 3, ...a, ...b, ...c, ...d];
console.timeEnd("spread-many");
console.time("flat-many");
for (i = 0; i < 1e2; i++) x = [1, 2, 3, a, b, c, d].flat();
console.timeEnd("flat-many");
I have two arrays, arr1 = [1,2,7,9,10] and arr2 = [40,50,70,80,30]. From these two arrays, I have a zero-filled array of length 15 that I want to populate using arr1 as the indexes and arr2 as the values: [0,40,50,0,0,0,0,70,0,80,30,0,0,0,0]
What is the code to do this?
Here is the solution:
var arr1 = [1,2,7,9,10]; // Add 0 to your array if you want first element of array3 to be replaced with arr2 element
// If you want first element like in example this would be correct
// var arr1 = [0,1,6,8,9];
var arr2 = [40,50,70,80,30];
var arr3 = []; //[40,50,0,0,0,0,70,0,80,30,0,0,0,0,0]
var arr3Length = 15;
var arr2Counter = 0;
for ( var i = 0; i < arr3Length; i ++ ) {
if ( arr1.includes(i) ) {
arr3.push(arr2[arr2Counter]);
arr2Counter ++;
} else {
arr3.push(0);
}
}
console.log(arr3);
JavaScript array starts with 0 element, not 1, so your first value is 0, not 40...
Here is a succinct way to do it without any for loop or if/else. You first create an array withs 0s and the appropriate length, and then you fill the slots.
const indices = [1, 2, 7, 9, 10]; // criteria 1
const values = [40, 50, 70, 80, 30]; // criteria 2
const length = 15; // criteria 3
const array = new Array(length).fill(0);
indices.forEach((idx, i) => array[idx] = values[i]);
console.log(array)
You could also calculate a default value for criteria 3 (length) if the length given is smaller than the last element of your index array.
lengthSafe = length < indices[indices.length-1] ? indices[indices.length-1] : length;
You should also make sure that your values array is not smaller than your indices array.
Aslo, beware, JavaScript array indexing starts at 0, not 1!
If you consider 1 to be your first index, do this instead:
indices.forEach((idx, i) => array[idx - 1] = values[i]);
Javascript is something new for me, and we have to do homework.
I have created new array:
var numbers = [1,2,3,4,5,6];
And with function forEeach I should achieve result like in console.log:
console.log(numbers[0]*numbers[1]+numbers[0]+numbers[1]);
I've tested many things, but I don't have any idea how to pull out signle init...
I know it should be simple, but I've stucked.
Thanks for help!
From your question looks like your problem is interacting with the current element of the forEach loop.
var numbers = [1,2,3,4,5,6]
// this will print every number in the array
// note that index numbers are not needed to get elements from the array
numbers.forEach(function(num){
console.log(num)
})
Now, if what you're trying t achieve is sum and multiply every int (as stated in the question title), you could do it like this
var numbers = [1,2,3,4,5,6]
var sumResult = 0
var multiplicationResult = 1
// the function will be evaluated for every element of the array
numbers.forEach(function(num){
sumResult += num
multiplicationResult *= num
})
console.log('Sum', sumResult)
console.log('Multiplication', multiplicationResult)
However, a more appropiate approach could be obtained by using reduce like this:
var numbers = [1,2,3,4,5,6]
var sumResult = numbers.reduce(function(result, num){
return num+result
}, 0)
var multiplicationResult = numbers.reduce(function(result, num){
return num*result
}, 1)
console.log('Sum', sumResult)
console.log('Multiplication', multiplicationResult)
Hope this helps.
More info:
Reduce # MDN
ForEach # MDN
To pull out a single number for the provided array you using the indexer/bracket notation which is specifying a number (length of array - 1) in brackets, like below:
var numbers = [1, 2, 3, 4, 5, 6];
numbers[0]; // selects the first number in the array
numbers[1]; // selects second number etc.
To sum up the numbers using forEach, simply do:
var sum = 0;
numbers.forEach(function(number) {
sum += number; // add number to sum
});
forEach goes through all the numbers in the numbers array, passing in each number to the function defined and then adds the number to the sum variable.
If you want your results, use map(). Unlike forEach(), map() will always return results in a new array. It wasn't very clear as to what expression you are expected to use or what the result of said expression should be so this demo will do the following on each iteration:
A = current value * next value
B = current value + next value
C = A + B;
Demo
const num = [1, 2, 3, 4, 5, 6];
let arr = num.map(function(n, idx, num) {
let next = num[idx + 1];
if (!next > 0) {
next = idx + 2;
}
let subSUM = n + next;
let subPRD = n * next;
let subRES = subPRD + subSUM;
return subRES;
});
console.log(arr);
Hey guys so for example I have an array:
myArray[5,4,1,2,1,4,5,6,7,8,9,10,1,2,1,5,3,2]
I'm sorting that array:
[1, 1, 1, 1, 10, 2, 2, 2, 3, 4, 4, 5, 5, 5, 6, 7, 8, 9]
And I want to delete only the two duplicates so the array I want will be
[10,2,3,5,6,7,8,9]
So i'm using splice:
for (var index = 0; index < myArray.length +1; ++myArray) {
if(myArray[index+1]== myArray[index]) {
myArray.splice(index);
myArray.splice[index+1];
}
}
But when I'm pushing more of the of the numbers, the results seem unpredictable
How to do this properly?
To clarify: The purpose is to eliminate the numbers which repeat an even number of times.
Here's another method, which checks for an odd number of elements by subtracting the indexOf the key from the lastIndexOf the key after sorting:
var myArray = [5,4,1,2,1,4,5,6,7,8,9,10,1,2,1,5,3,2];
var result = myArray.sort().filter(function(key, idx) {
return myArray.indexOf(key) === idx && //handle first instance only
(myArray.lastIndexOf(key) - myArray.indexOf(key)) % 2 === 0;
});
console.log(result);
Here is an ECMAScript2015 solution:
var myArray = [5,4,1,2,1,4,5,6,7,8,9,10,1,2,1,5,3,2];
var count = myArray.reduce((count, num) =>
(count[num] = (count[num] || 0) + 1, count), {});
myArray = Object.keys(count).filter(num => count[num] % 2).map(Number);
console.log(myArray);
The count variable is an object of which the properties are the numbers in the original array. The value for each of these properties is the number of occurrences of that number in the original array.
The keys are then iterated to get only those into the final array that have a value (i.e. occurrences) that is odd. As object properties are iterated in numerical order (when numerical), the result is automatically sorted numerically.
About your code:
The for loop you have, has some issues:
for (var index = 0; index < myArray.length +1; ++myArray) {
if(myArray[index+1]== myArray[index]) {
myArray.splice(index);
myArray.splice[index+1];
}
}
Certainly you don't want to increment myArray, but index.
The boundary condition should not be length+1 but length-1 as in the body you have myArray[index+1] and don't want to go out of bounds there.
But more importantly, doing splice in your for loop will make the elements shift position, and as you then still increment index, you will skip elements.
In short, you should not use splice in such a loop. You can solve this by going in the reverse direction, and start at the end of the array working towards the beginning.
But the above proposed code does not have this problem and also saves you the step of sorting.
You can do this with two reduce and Object.keys(). First add values to object and then check each value with % 2 and add to array.
var myArray = [5,4,1,2,1,4,5,6,7,8,9,10,1,2,1,5,3,2];
var obj = myArray.reduce(function(o, e) {
o[e] = (o[e] || 0)+1;
return o;
}, {})
var result = Object.keys(obj).reduce(function(r, e) {
if(obj[e] % 2) r.push(Number(e));
return r;
}, []);
console.log(result)
I have the following object
var mapping = {
0: ['A','B','C'],
1: ['D','E','F'],
2: ['G', 'H', 'I'],
---
---
9: ['X','Z']
}
There is a function that references the above object and finds all the possible combinations. For example, we have
function combination(value){}
combination([1,0]); // DA, DB, DC, EA, EB, EC, FA, FB, FC
So in the above invocation the keys at "1" and "0" from the map object will be referenced and all the possible combinations for those two will be returned.
I think the best way to solve this would be to use a recursion, but i just can't seem to wrap my head around this
Not just recursion you can use multiple for loops to achieve this
for (var i = 0 ; i < mapping[index1].length ; i++)
{
for (var j = 0 ; j < mapping[index2].length ; j++)
{
resultArray.push(mapping[i][j]);
}
}
here resultArray is the output array, index1, index2 are the indexes passed
Close enough:
var mapping = {
0: ['A', 'B', 'C'],
1: ['D', 'E', 'F'],
2: ['G', 'H', 'I'],
9: ['X', 'Z']
}
function combine(array, index1, index2) {
var result = array[index1].map(function (el1) {
return array[index2].map(function (el2) {
return [el1, el2].join('');
})
});
return [].concat.apply([], result);
}
function combineAll(array, indices) {
var result = [];
for (var i = 0; i < indices.length - 1; i++) {
var index = indices[i];
var nextIndex = indices[i + 1];
result = result.concat(combine(array, index, nextIndex));
}
return result;
}
var combinations = combineAll(mapping, [1, 0, 9]);
console.log(combinations);
document.write(JSON.stringify(combinations, null, 2));
To find all possible combination we have to iterate over mapping object as well as array corresponding to given key, here i create two functions combination which will iterate over mapping object keys and map which will iterate of array corresponding to each given key:
var mapping = {
0: ['A','B','C'],
1: ['D','E','F'],
2: ['G', 'H', 'I'],
3: ['J', 'K', 'L'],
4: ['M', 'N', 'O']
}
var resultArray = [];
function combination(x){
for(var i=0;i<x.length;i++){
for(var j=i+1;j<x.length;j++){
map(x[i],x[j])
}
}
}
function map(index1,index2){
for (var i in mapping[index1])
{
if(mapping[index1].hasOwnProperty(i)){
for (var j in mapping[index2])
{
if(mapping[index2].hasOwnProperty(j)){
resultArray.push(mapping[index1][i]+''+mapping[index2][j]);
}
}
}
}
}
combination([0,2,1,4])
console.log(resultArray);
You can use recursion in order to solve this problem.
Simply iterate through the indices, and try to add every corresponding item recursively.
I have implemented a working JS function for you:
function combination(o) { // just a wrapper for convenient usage
var current = [];
function step() { // recursive function
if (current.length === o.indices.length) { // combination is ready
o.callback(current); // callback
return; // and leave recursion
}
// current.length is a current position (0, 1, 2, 3 etc.) for which we find a value
// o.indices[o.current.length] is an index of mapping for current position (0, 2, 2, 1 in a demo below)
// o.mapping[o.indices[o.current.length]] is simply a row
o.mapping[o.indices[current.length]].forEach(function(x) {
current.push(x);
step();
current.pop();
});
}
step(); // start recursion
}
You can use it this way:
combination({
mapping: { // your mapping
0: ['A', 'B', 'C'],
1: ['D', 'E', 'F'],
2: ['G', 'H', 'I']
},
indices: [0, 2, 2, 1], // indices may repeat
callback: function(x) { // callback will be called every time we find a combination
document.body.innerHTML += x + "<br/>"; // x is an array
}
});
Here is the working JSFiddle demo.
Following is a solution using recursion.
It does a DFS (Depth First Traversal ) to find all the paths of length corresponding to the input array.
For every dive to the next level, the array gets shortened using slice(1). The original array is not modified and the pattern repeats. When there are no more elements in the array, the path is printed.
I have added a count to see how many combinations are generated. The count should be a product of the lengths of all arrays in the initial input array.
That is for snippet with input array [2,0,3,7] , the product is 3 * 3 * 4 * 3 = 108, i.e 108 combinations.
Essentially picture a tree with the first level nodes with all mapping[2] elements, each of those have mapping[0] children making level 2 of the tree, each level 2 then has mapping[3] elements as children at level 3 and finally mapping[7] would make up the leaf nodes of the tree. This can go to any level based on your input array and your mapping configuration.
The code below does a recursive traversal of the above tree, each time going from root to each leaf node and prints out that path.
var mapping = {
0: ['0A','0B','0C'],
1: ['1A','1B','1C'],
2: ['2A','2B','2C'],
3: ['3A','3B','3C', '3D'],
4: ['4A','4B','4C'],
5: ['5A','5B','5C'],
6: ['6A','6B','6C'],
7: ['7A','7B','7C']
}
var count = 0;
function traverse(arr, comb) {
if(!arr.length) {
console.log(++count + " : " + comb+"\n");
return;
}
for(var j =0; j < mapping[arr[0]].length; j++)
traverse(arr.slice(1), comb + " " + mapping[arr[0]][j]);
}
traverse([2,0,3,7],"");