Is there a shortcut to accessing elements of an array using an array of indices rather than going one index at a time?
Example (this doesn't work):
var array = ["One", "Two", "Three", "Four"];
var indices = [1, 3];
var result = array[indices];
where result would be ["Two", "Four"].
You can make one and have it available to all Arrays if you've no qualms about extending native prototypes in your environment.
Array.prototype.atIndices = function(ind) {
var result = [];
for (var i = 0; i < arguments.length; i++) {
if (arguments[i] in this)
result.push(this[arguments[i]])
}
return result;
}
var result = array.atIndices(1,3);
You could also have it check to see if an Array was passed, or a mix of indices and Arrays.
Array.prototype.atIndices = function(ind) {
var result = [];
for (var i = 0; i < arguments.length; i++) {
if (Array.isArray(arguments[i]))
result.push.apply(result, this.atIndices.apply(this, arguments[i]))
else if (arguments[i] in this)
result.push(this[arguments[i]])
}
return result;
}
This will actually flatten out all Arrays, so they could be as deeply nested as you want.
var result = array.atIndices(1, [3, [5]]);
Now there is:
function pluck(arr, indices) {
var result = [],
i = 0,
len = indices.length;
for (; i < len; i++) {
result.push(arr[indices[i]]);
}
return result;
}
As an alternative to rolling your own, if you have access to Lo-Dash (which you should totally use because it is awesome) its at function does exactly what you want.
Your usage would be:
var result = _.at(array, indices);
See: http://lodash.com/docs#at
Related
I'm trying to flatten an array with randomly nested arrays inside. I'm not sure why the function I wrote ends up in an infinite loop:
let array = [1, 2, [3]]
var final_array = []
function flattener(array){
for(i = 0; i < array.length; i++){
if(array[i] instanceof Array){
flattener(array[i])
}else{
final_array.push(array[i])
}
}
}
flattener(array)
What I think SHOULD happen is:
When I'm in the for loop checking for [3], it goes into the if statement, flattener gets called again, it resolves, and then I exit the if statement.
Instead, the if statement keeps calling to check [3] infinitely, and I'm not sure why this happens.
The problem is you didn't declare the i variable, so it's leaking into the global space and being reset when it recurses.
Change:
for(i = 0; i < array.length; i++){
To:
for(var i = 0; i < array.length; i++){
This is another approach using Array.reduce and Array.concat.
/**
* Flattens an array of arrays into one-dimensional array
* #param {Array} arr: the array to be flattened
* #return {Array}
*/
function flatten(arr) {
return arr.reduce(function (flattened, cvalue) {
return flattened.concat(Array.isArray(cvalue) ? flatten(cvalue) : cvalue);
}, []); // initial value of flattened array []
}
Testing it...
let array = [1, 2, [3]]
var falttened = flatten(array)
Take a look at his gist: Array flatten
Array#concat plus Array#map is yet another way you can achieve this
var flattener = arr => [].concat.apply([], arr.map(item=>Array.isArray(item) ? flattener(item) : item));
or the ES5 version
var flattener = function flattener(arr) {
return [].concat.apply([], arr.map(function (item) {
return Array.isArray(item) ? flattener(item) : item;
}));
};
Change
for(i = 0; i < array.length; i++)
to
for(var i = 0; i < array.length; i++)
I've created a simple forEach function and I'm trying to understand why, when I run it with myArray, it doesn't mutate the array even though I run element*2.
function forEach(array, callback) {
for (var i = 0; i < array.length; i++) {
callback(array[i],i,array)
};
}
var myArray = [1,2,3]
forEach(myArray,function(element){element*2})
console.log(myArray)///[1,2,3]
You have to modify the array in the for loop, like this:
function forEach(array, callback) {
for (var i = 0; i < array.length; i++) {
array[i] = callback(array[i],i,array)
};
}
var myArray = [1,2,3]
forEach(myArray,function(element){return element*2})
console.log(myArray)
As we were discussing in the comments, the best way would be to implement something like the map function: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/map
function map(array, callback) {
var out = [];
for (var i = 0; i < array.length; i++) {
out.push(callback(array[i],i,array))
};
return out;
}
var myArray = [1,2,3]
var myOtherArray = map(myArray,function(element){return element*2})
console.log(myArray)
console.log(myOtherArray)
This way myArray is not touched, you create a new one. This is usually the best option, but sometimes you may want to modify it in place, because it is huge or for some other (good?) reason. In that case you can use the first option.
You should assign new array element value, because primitive types (like numbers in your case) are immutable, so element * 2 does not modify element.
To do the job, you should not touch you current forEach implementation, because forEach is not supposed to return values from callback (this is not map). In this case you should do something like this:
function forEach(array, callback) {
for (var i = 0; i < array.length; i++) {
callback(array[i], i, array);
}
}
var myArray = [1,2,3];
forEach(myArray, function(element, i, arr) {
arr[i] = element * 2;
});
document.write(JSON.stringify( myArray ));
This should work, explicitly assigning the variable.
function forEach(array, callback) {
for (var i = 0; i < array.length; i++) {
array[i] = callback(array[i])
};
}
var myArray = [1,2,3]
forEach(myArray,function(element){return element*2})
console.log(myArray)///[1,2,3]
Yep, bad answer. This [snippet] would do it though.
Anyway, in modern browsers we have Array.forEach to availability
function foreach(array, callback) {
for (var i = 0; i < array.length; i++) {
array[i] = callback(array[i]);
// ^ assign the new value (from the callback function)
};
}
var myArray = [1,2,3]
foreach( myArray, function (element){ return element * 2 } );
// ^ return the new value
document.querySelector('#result').textContent = myArray;
<pre id="result"></pre>
I have two arrays
var arr1 = ['wq','qw','qq'];
var arr2 = ['wq','wq','wq','qw','qw','qw','qw','qq','qq'];
Below what i did is matching arr1 values with arr2. If the array contains same values i pushed the values into newArr.
var newArr = [];
for (var i=0;i<arr1.length;i++) {
newArr[i] = [];
}
for (var i=0;i<arr2.length;i++) {
for (var j=0;j<arr1.length;j++) {
if (arr2[i].indexOf(arr1[j]) != -1)
newArr[j].push(arr2[i]);
}
}
console.log(newArr[1]); //newArr[0] = ['wq','wq','wq'];//In second output array newArr[1] = ['qw','qw','qw','qw'];
Is there any easy way to solve this without using two for loops. Better i need a solution in javascript
Maybe use indexOf():
var count = 0;
for (var i = 0; i < arr1.length; i++) {
if (arr2.indexOf(arr1[i]) != -1) {
count++;
// if you just need a value to be present in both arrays to add it
// to the new array, then you can do it here
// arr1[i] will be in both arrays if you enter this if clause
}
}
if (count == arr1.length) {
// all array 1 values are present in array 2
} else {
// some or all values of array 1 are not present in array 2
}
Your own way wasn't totally wrong, you just had to check if the element was index of the array and not of an element in the array.
var arr1 = ['wq','qw','qq'];
var arr2 = ['wq','wq','wq','qw','qw','qw','qw','qq','qq'];
var newArr = [];
for (var i in arr1) {
newArr[i] = [];
}
for (var i in arr2) {
var j = arr1.indexOf(arr2[i]);
if (j != -1) {
newArr[j].push(arr2[i]);
}
}
This way you removed the nested for loop and it still gives you the result you asked for.
var arr1 = ['wq','qw','qq','pppp'];
var arr2 = ['wq','wq','wq','qw','qw','qw','qw','qq','qq'];
function intersect(a, b) {
var d = {};
var results = [];
for (var i = 0; i
d[b[i]] = true;
}
for (var j = 0; j
if (d[a[j]])
results.push(a[j]);
}
return results;
}
var result_array = intersect(arr1,arr2);
// result_array will be like you want ['wq','wq','wq'];
Let's say we have two Arrays in JavaScript, [3,4,7] and [5,6].
Without sorting or using .apply, what is the best way to insert [5,6] into [3,4,7] at index 2 in order to achieve the resulting Array: [3,4,5,6,7]?
Don't know how you're defining "best way", but you can do this:
a.slice(0,2).concat(b,a.slice(2));
Unless you're saying you actually want to mutate the a Array, in which case you could do this:
var c = a.splice(2);
for (var i = 0; i < b.length + c.length; i++) {
a.push(i < b.length ? b[i] : c[i-b.length]);
}
This behavior of .splice() to split the Array in two parts may have issues in older IE that would need to be patched.
Or this would probably be better:
var c = b.concat(a.splice(2));
for (var i = 0; i < c.length; i++) {
a.push(c[i]);
}
Same caveat about .splice().
function splice(arrayOne, arrayTwo, index) {
var result = [];
for (var i = 0; i < arrayOne.length; i++) {
if (i == index) {
result = result.concat(arrayTwo);
}
result.push(arrayOne[i]);
}
return result;
}
Not really sure why you don't want to use the native methods, but here's a fairly naive solution with just loops:
function doInsert(index, items, arr) {
var insertLen = items.length,
current;
for (i = 0; i < insertLen; ++i) {
current = i + index;
arr[current + insertLen - 1] = arr[current];
arr[current] = items[i];
}
}
var arr = [3, 4, 7];
doInsert(2, [5, 6], arr);
console.log(arr);
Hey i have a simple question i cant find an answer,
i´m trying to generate some raw-data for a chart
lets say i have an array like :
[1,0,0,1,2,0]
is there a way to make an array out of it that has nested arrays that represent the count of duplicate entrys ?
[[0,3],[1,2],[2,1]]
here is some code that does the trick, but saves the count as objects
var array = [1,0,0,1,2,0];
var length = array.length;
var objectCounter = {};
for (i = 0; i < length; i++) {
var currentMemboerOfArrayKey = JSON.stringify(array[i]);
var currentMemboerOfArrayValue = array[i];
if (objectCounter[currentMemboerOfArrayKey] === undefined){
objectCounter[currentMemboerOfArrayKey] = 1;
}else{
objectCounter[currentMemboerOfArrayKey]++;
}
}
but objectCounter returns them like
{0:3,1:2,2:1}
but i need it as an array i specified above ?
for any help, thanks in advance
Try
var array = [1, 0, 0, 1, 2, 0];
function counter(array) {
var counter = [],
map = {}, length = array.length;
$.each(array, function (i, val) {
var arr = map[val];
if (!arr) {
map[val] = arr = [val, 0];
counter.push(arr);
}
arr[1] += 1;
})
return counter;
}
console.log(JSON.stringify(counter(array)))
Demo: Fiddle
You can turn your object into an array easily:
var obj = {0:3,1:2,2:1};
var arr = [];
for (var key in obj) {
// optional check against Object.prototype changes
if (obj.hasOwnProperty(key)) {
arr.push([+key, obj[key]]);
}
}
Note: The object keys are strings, so i converted them back to numbers when placed in the array.
Functional way of doing this, with Array.reduce and Array.map
var data = [1,0,0,1,2,0];
var result = data.reduce(function(counts, current) {
counts[current] = current in counts ? counts[current] + 1: 1;
return counts;
}, {});
result = Object.keys(result).map(function(current){
return [parseInt(current), result[current]];
});
console.log(result);
Output
[ [ 0, 3 ], [ 1, 2 ], [ 2, 1 ] ]
Try:
var data = [1,0,0,1,2,0];
var len = data.length;
var ndata = [];
for(var i=0;i<len;i++){
var count = 0;
for(var j=i+1;j<len;j++){
if(data[i] == data[i]){
count ++;
}
}
var a = [];
a.push(data[i]);
a.push(count);
ndata.push(a);
}
console.log(ndata)
DEMO here.
First you need to map the array to an associative object
var arr = [1,0,0,1,2,0];
var obj = {};
for (var i = 0; i < arr.length; i++) {
if (obj[arr[i]] == undefined) {
obj[arr[i]] = 0;
}
obj[arr[i]] += 1;
}
Then you can easily turn that object into a 2d matrix like so:
arr = [];
for (var k in obj) {
arr.push([k, obj[k]]);
}
alert(JSON.stringify(arr));
Your existing object can be turned into an array with a simple for..in loop. Also your existing code that produces that object can be simplified. Encapsulate both parts in a function and you get something like this:
function countArrayValues(array) {
var counter = {},
result = [];
for (var i = 0, len = array.length; i < len; i++)
if (array[i] in counter)
counter[array[i]]++;
else
counter[array[i]] = 1;
for (i in counter)
result.push([+i, counter[i]]);
return result;
}
console.log( countArrayValues([1,0,0,1,2,0]) );
Demo: http://jsfiddle.net/hxRz2/