Related
I'm working on improving my javascript skills and I want to understand the mechanics behind pop() and push(). I'm reading Marijn Haverbeke's Eloquent Javascript book and I'm working on chapter 4's Reversing Array exercise. I was able to solve the problem; however, I ran into an interesting quirk. My first code attempt was:
var arr = ['a', 'b', 'c', 'd'];
function reverseArray(array){
var newArray = [];
console.log(array.length);
for(var i = 0; i <= array.length; i++){
newArray[i] = array.pop();
};
return newArray;
};
reverseArray(arr);
This result was ['d', 'c', 'b'] and the the 'a' was not resolving. I don't understand why? Can someone explain?
My second code attempt was:
var arr = ['a', 'b', 'c', 'd'];
function reverseArray(array){
var newArray = [];
console.log(array.length);
for(var i = array.length - 1; i >= 0; i--){
newArray.push(array[i]);
};
return newArray;
};
console.log(reverseArray(arr));
This resulted in the correct reversal of the array: ['d', 'c', 'b', 'a']. Can someone explain why this worked?
Here lies your problem:
for(var i = 0; i <= array.length; i++){
newArray[i] = array.pop();
};
for each iteration:
i = 0 array.length: 4 //d
i = 1 array.length: 3 //c
i = 2 array.length: 2 //b
i = 3 array.length: 1 //a -- wont print
now your loop stops working because you told so in:-
i <= array.length
//3 <= 1 will return false so for loop stops
Not sure if you noticed, but push() and pop() change .length property of an Array
The first function doesn't return the expected result because as you pop its elements it gets shorter. Each turn the loop compares the arrays new length.
You could store the arrays initial length and compare against it:
var arr = ['a', 'b', 'c', 'd'];
function reverseArray(array){
var newArray = [],
length = array.length; // save the initial length
for(var i = 0; i < length; i++){
newArray[i] = array.pop();
};
return newArray;
};
console.log(reverseArray(arr));
I have an array like:
A = ['a', 'del', 'b', 'del', 'c']
how can i remove the elements del such that the result is,
B = ['a', 'b', 'c']
I tried the pop and indexOf method but was unable
Use filter() for filtering elements from an array
var A = ['a', 'del', 'b', 'del', 'c'];
var B = A.filter(function(v) {
return v != 'del';
});
console.log(B);
For older browser check polyfill option of filter method.
In case if you want to remove element from existing array then use splice() with a for loop
var A = ['a', 'del', 'b', 'del', 'c'];
for (var i = 0; i < A.length; i++) {
if (A[i] == 'del') {
A.splice(i, 1); // remove the eleemnt from array
i--; // decrement i since one one eleemnt removed from the array
}
}
console.log(A);
function chunk(arr, size) {
var newr = [];
var temp = [];
for (var i = 0; i < arr.length; i++) {
if (temp.length != size) {
temp.push(arr[i]);
} else {
newr.push(temp);
temp = [];
}
}
return newr;
}
chunk(['a', 'b', 'c', 'd'], 2);
Can someone help me why my code isn't working? It's just displaying the first chunk of array and ignoring the second.
Here is one efficient way of doing it using Array.splice():
function chunk(arr, size) {
var out = [];
while(arr.length) out.push(arr.splice(0, size));
return out;
}
Calling chunk(['a', 'b', 'c', 'd'], 2); will return:
[
["a", "b"],
["c", "d"]
]
Note: The above method will modify the original array that is passed into the function.
To fix your code, try this
function chunk(arr, size) {
var newr = [];
var temp = [];
for (var i = 0; i < arr.length; i++) {
temp.push(arr[i]);
if(temp.length==size || i==arr.length-1) {
newr.push(temp);
temp = [];
}
}
return newr;
}
chunk(['a', 'b', 'c', 'd'], 2); // results in [['a','b'],['c','d']]
chunk(['a', 'b', 'c', 'd', 'e'], 2); // results in [['a','b'],['c','d'],['e']]
Why your previous code doesn't work
Your condition works well. The last iteration does collect the last chunk ['c','d'] in temp correctly but it is not added to the newr list. Thus, a little modification to cover this issue is made in my code as shown above.
The question doesn't make much sense but not sure how to word it without an example. If someone can word it better, feel free to edit it.
Let's say I have an array of arrays such as this:
[ ['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e'] ]
I would like the output to be:
['a', 'a', 'b', 'b', 'b', 'c', 'd', 'e']
Not sure if there is an easy way to do this in javascript/jquery/underscore. One way I could think of is to look through each of these arrays and count up the number of times each element shows up and keep track of the maximum amount of times it shows up. Then I can recreate it. But that seems pretty slow considering that my arrays can be very large.
You need to:
Loop over each inner array and count the values
Store each value and its count (if higher than current count) in a counter variable
In the end, convert the value and counts into an array
Following code shows a rough outline of the process. Remember to replace .forEach and for..in with appropriate code:
var input = [['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e']],
inputCount = {};
input.forEach(function(inner) {
var innerCount = {};
inner.forEach(function(value) {
innerCount[value] = innerCount[value] ? innerCount[value] + 1 : 1;
});
var value;
for (value in innerCount) {
inputCount[value] = inputCount[value] ? Math.max(inputCount[value], innerCount[value]) : innerCount[value];
}
});
console.log(inputCount);
// Object {a: 2, b: 3, c: 1, d: 1, e: 1}
After messing around, I found a solution but not sure if I like it enough to use. I would probably use it if I can't think of another one.
I would use underscorejs countBy to get the count of all the elements.
var array = [ ['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e'] ];
var count = _.map(array, function(inner) {
return _.countBy(inner, function(element) {
return element;
});
});
var total = {};
_.each(_.uniq(_.flatten(array)), function(element) {
var max = _.max(count, function(countedElement) {
return countedElement[element];
});
total[element] = max[element];
});
console.log(total); // {a: 2, b: 3, c: 1, d: 1, e: 1}
Then I would recreate the array with that total.
Here is example of simple nested loop approach:
var input = [ ['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e'] ];
var countMap = {};
// iterate outer array
for (i=0; i < input.length; i++) {
// iterate inner array
for (j=0; j < input[i].length; j++) {
// increment map counter
var value = input[i][j];
if (countMap[input[i][j]] === undefined) {
countMap[value] = 1;
} else {
countMap[value]++;
}
}
}
console.log(countMap); // output such as {'a':2, 'b':4, 'c':1, 'd':1, 'e':1}
Not the most efficient solution but it should describe you the process:
var big = [ ['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e'] ];
function map(arr){
var map = {}
for (var i=arr.length-1; i>-1; i--){
if(arr[i] in map) map[arr[i]]++;
else map[arr[i]] = 1;
}
return map;
}
function reduce(matrix){
var arrMap = {};
for (var i=matrix.length-1; i>-1; i--){
var arrRes = map(matrix[i]);
for (var key in arrRes){
if( !arrMap[key] || arrMap[key] < arrRes[key])
arrMap[key] = arrRes[key];
}
}
return arrMap;
}
function calc(matrix){
var res = [],
arrMap = reduce(matrix);
for (var key in arrMap){
while(arrMap[key] > 0 ){
res.push(key);
arrMap[key]--;
}
}
return res;
}
console.log(calc(big));
// Array [ "e", "b", "b", "b", "a", "a", "d", "c" ]
var arr = ['a', 'b', 'c', 'd', 'e', 'f'];
var point = 'c';
How can I split the "arr" into two arrays based on the "point" variable, like:
['a', 'b']
and
['d', 'e', 'f']
var arr2 = ['a', 'b', 'c', 'd', 'e', 'f'];
arr = arr2.splice(0, arr2.indexOf('c'));
To remove 'c' from arr2:
arr2.splice(0,1);
arr contains the first two elements and arr2 contains the last three.
This makes some assumptions (like arr2 will always contain the 'point' at first assignment), so add some correctness checking for border cases as necessary.
Use indexOf and slice
var arr = ['a', 'b', 'c', 'd', 'e', 'f'];
var indexToSplit = arr.indexOf('c');
var first = arr.slice(0, indexToSplit);
var second = arr.slice(indexToSplit + 1);
console.log({first, second});
Sharing this convenience function that I ended up making after visiting this page.
function chunkArray(arr,n){
var chunkLength = Math.max(arr.length/n ,1);
var chunks = [];
for (var i = 0; i < n; i++) {
if(chunkLength*(i+1)<=arr.length)chunks.push(arr.slice(chunkLength*i, chunkLength*(i+1)));
}
return chunks;
}
Sample usage:
chunkArray([1,2,3,4,5,6],2);
//returns [[1,2,3],[4,5,6]]
chunkArray([1,2,3,4,5,6,7],2);
//returns [[1,2,3],[4,5,6,7]]
chunkArray([1,2,3,4,5,6],3);
//returns [[1,2],[3,4],[5,6]]
chunkArray([1,2,3,4,5,6,7,8],3);
//returns [[1,2],[3,4,5],[6,7,8]]
chunkArray([1,2,3,4,5,6,7,8],42);//over chunk
//returns [[1],[2],[3],[4],[5],[6],[7],[8]]
Try this one:
var arr = ['a', 'b', 'c', 'd', 'e', 'f'];
var point = 'c';
var idx = arr.indexOf(point);
arr.slice(0, idx) // ["a", "b"]
arr.slice(idx + 1) // ["d", "e", "f"]
var arr = ['a', 'b', 'c', 'd', 'e', 'f'];
var point = 'c';
Array.prototype.exists = function(search){
for (var i=0; i<this.length; i++) {
if (this[i] == search) return i;
}
return false;
}
if(i=arr.exists(point))
{
var neewArr=arr.splice(i);
neewArr.shift(0);
console.log(arr); // output: ["a", "b"]
console.log(neewArr); // output: ["d", "e", "f"]
}
Here is an example.
var arr = ['a', 'b', 'c', 'd', 'e', 'f'];
var point = 'c';
var i = arr.indexOf(point);
var firstHalf, secondHalf, end, start;
if (i>0) {
firstHalf = arr.slice(0, i);
secondHalf = arr.slice(i + 1, arr.length);
}
//this should get you started. Can you think of what edge cases you should test for to fix?
//what happens when point is at the start or the end of the array?
When splitting the array you are going to want to create two new arrays that will include what you are splitting, for example arr1 and arr2. To populate this arrays you are going to want to do something like this:
var arr1, arr2; // new arrays
int position = 0; // start position of second array
for(int i = 0; i <= arr.length(); i++){
if(arr[i] = point){ //when it finds the variable it stops adding to first array
//starts adding to second array
for(int j = i+1; j <= arr.length; j++){
arr2[position] = arr[j];
position++; //because we want to add from beginning of array i used this variable
}
break;
}
// add to first array
else{
arr1[i] = arr[i];
}
}
There are different ways to do this! good luck!
Yet another suggestion:
var segments = arr.join( '' ).split( point ).map(function( part ) {
return part.split( '' );
});
now segments contains an array of arrays:
[["a", "b"], ["d", "e", "f"]]
and can get accessed like
segments[ 0 ]; // ["a", "b"]
segments[ 1 ]; // ["d", "e", "f"]
if you want to split into equal half; why no simple while loop ?
var arr = ['a', 'b', 'c', 'd', 'e', 'f'];
var c=[];
while(arr.length > c.length){
c.push(arr.splice(arr.length-1)[0]);
}
Kaboom :).
Separate two arrays with given array elements as string array and number array;
let arr = [21,'hh',33,'kk',55,66,8898,'rtrt'];
arrStrNum = (arr) => {
let str = [],num = [];
for(let i = 0;i<arr.length;i++){
if(typeof arr[i] == "string"){
str.push(arr[i]);
}else if(typeof arr[i] == "number"){
num.push(arr[i]);
}
}
return [str, num]
}
let ans = arrStrNum(arr);
let str = ans[0];
let num = ans[1];
console.log(str);
console.log(num);