I'm trying to make an array of empty arrays, the amount of which depends on N. Currently, I have this:
var seqList = [];
for(var i = 0; i < N; i++) {
seqList.push([]);
}
Is this the most efficient way of doing it? Or might there be another way?
Your method is the most efficient one. You can also use Array.fill method from ES6 but it is not the most efficient.
let n=10;
let array=Array.from({ length: n }, () => []);
console.log(array);
When you are using let array=[] you're telling the interpreter to create a new runtime array.
If you use:var a = new Array() you're telling the interpreterthat you want to call the constructor Array , generate an object and creating your array.
Array#fill is the cleanest
let count = 10;
let seqList = Array(count).fill([]);
Update:
After being schooled by #deceze I would rather use since the example above fails is a horribly subtle way.
let count = 10;
let seqList = Array(count).fill(0).map(_ => []);
Is it better than your attempt? Probably not. I've just become so used to reading map/reduce, I prefer it. YMMV
Related
I have a list that has objects with a varying amount of keys. I want to make sure that I get the index from the list of the object with the most keys OR the reference to the object itself. What is the best way to do this?
My current approach is:
let index = -1;
let numKeys = 0;
for(var i = 0; i < mylistofobjects.length; i++) {
if(Object.keys(mylistofobjects[i]).length > numKeys) {
index = i;
}
}
// by the end, index has the most keys
Is there a smarter/shorter way to do this that would require less code in this day and age? If the way to get the object reference is shorter than the way to get the index number.. I would prefer the object reference.
One option is to reduce, keeping in the accumulator the object with the most keys found so far:
const objWithMostKeys = mylistofobjects.reduce((bestSoFar, thisObj) => (
Object.keys(bestSoFar).length >= Object.keys(thisObj).length ? bestSoFar : thisObj
));
It's not entirely efficient because it checks the accumulator's number of keys on every iteration, rather than caching it, but caching it will require a bit more code:
let maxKeyCount = Object.keys(mylistofobjects[0]).length;
const objWithMostKeys = mylistofobjects.reduce((bestSoFar, currObj) => {
const currKeyCount = Object.keys(currObj).length;
if (currKeyCount > maxKeyCount) {
maxKeyCount = currKeyCount;
return currObj;
}
return bestSoFar;
});
This assumes that the mylistofobjects isn't empty. If that's a possibility, probably add a .length check beforehand, and return early / throw an error (or whatever you need to do) instead of proceeding.
I have an assignment which i need to sole but i am really stuck and can't make a progress. The assignment consist in an array of elements like this
const appleHolderLine = ['Rome', 'Ambrosia', 'Rome', 'RedDelicious', 'Akane','RedDelicious', 'SweeTango', 'RedDelicious', 'RedDelicious', 'Opal', 'Winesap', 'RedDelicious', 'Empire', 'RedDelicious', 'Liberty'];
Firstly it is needed to declare a variable lineCount which count for every element of the array and a reference to an object called appleMap.
Than the challenge consist in looping through the array and the elements of the array would be the object keys with no duplicates and the values would be an array of idexes of the specific element place of the array. To give an example how it should look like:
Example:
const appleHolderLine = ['GreenApples', 'RedDelicious','OrangeApples', 'PurpleApples', 'RedDelicious']
console.log (lineCount, appleMap)
Should Log:
5, {'GreenApples':[0], 'RedDelicious': [1,4], 'OrangeApples':[2], 'PurpleApples': [3]}
My progress so far
var lineCount = 0;
var appleMap = {};
for (let i = 0; i < appleHolderLine.length; i++){
lineCount++;
// if element in the array exist in the array
appleMap[appleHolderLine[i]] = [i];
}
Could you give me a hint of how to solve this, i am really stuck.
Basically you can create an empty array the first time and keep pushing like below
var lineCount = 0;
var appleMap = {};
for (let i = 0; i < appleHolderLine.length; i++){
lineCount++;
if(!appleMap[appleHolderLine[i]])
appleMap[appleHolderLine[i]] = []
appleMap[appleHolderLine[i]].push(i);
}
You could use Array.prototype.reduce which is a more advanced construct javascript provides. Please refer to answer by CodeManiac below for the same.
The above answer is to clarify the basic idea and hint on how you could think
Also, lineCount can be obtained by using appleHolderLine.length directly.
You don't need an extra variable ( Line count ) here, simply loop over the value use, use the index to access value, check if there's nothing present for that key then just initialize it with empty array, push index to the key in each iteration
const appleHolderLine = ['GreenApples', 'RedDelicious','OrangeApples', 'PurpleApples', 'RedDelicious']
var appleMap = {};
for (let i = 0; i < appleHolderLine.length; i++){
if(!appleMap[appleHolderLine[i]]){
appleMap[appleHolderLine[i]] = []
}
appleMap[appleHolderLine[i]].push(i);
}
console.log(appleMap)
You can simply use reduce
const appleHolderLine = ['GreenApples', 'RedDelicious','OrangeApples', 'PurpleApples', 'RedDelicious']
let final = appleHolderLine.reduce((op,inp,i)=>{
op[inp] = op[inp] || []
op[inp].push(i)
return op
},{})
console.log(final)
Line count is simply same as length of array, let lineCount = appleHolderLine.length
I suppose, the shortest answer is the functional one.
const appleHolderLine = ['GreenApples', 'RedDelicious','OrangeApples', 'PurpleApples', 'RedDelicious']
result = appleHolderLine.reduce((a,c,i) => { if(a[c]) a[c].push(i); else a[c]=[i]; return a; }, {})
console.log(result)
But I am not sure that you are expected to deliver a functional solution. Still, you might find it useful. The idea is that the reduce method starts with an empty object and iterates through the array. In each iteration, it checks if the current element c is already a field of the accumulator a. If so adds its index i to the specific field, if not, initializes the field with the current element as name and the index as a single-element array as value.
I am trying to understand for loops totally. I made my research and understand a little.
I Know loops like
for(var i = 0; i < 5; i++) { console.log(i) }
Which means continue to increment i starting from 0 as log as i is less than 5
I also know loops like
var a = [];
a[5] = 5;
for (var x in a) {
console.log(x);
}
Which means loop for x in a and would log 5;
Was searching playing around researching and then i see something like
function aNumber() {
var aInt = 521;
var intString = aInt.toString();
var intLength = intString.length;
var result = 0;
for (var i in intString) {
result += Math.pow((+intString[i]), intLength);
}
console.log(result);
//...
}
aNumber();
I understand the conversion of int to string. But the loop is new to me.
I know what the Math.pow() function does like it take to parameters (Math.pow(2,2) is same as 2**2) and the + in +intString passes the string as an int What i don't really understand is this part here
result += Math.pow((+intString[i]), intLength);
Its making the whole loop look confusing.
Can someone help explain it for me in simple terms just like i explained the others? Thanks
for..in loops iterate over the enumerable property names on the object (including properties inherited from the prototype). Because strings' enumerable properties are always their numeric indicies and nothing else, the line:
for (var i in intString)
can be replaced with
for (let i = 0; i < intString.length; i++)
while leaving the rest of the code the same, and it will perform identically. The intString[i] expression just refers to the current character being iterated over.
But I wouldn't recommend using for..in loops in most cases - it's not hard to confuse with for..of (which is quite different), and array methods are often nicer to work with. For example, the code that generates the result in your code can be replaced with the use of Array.prototype.reduce, which can generate the result at once, without any reassignment:
const intString = '521';
const intLength = intString.length;
const result = Array.prototype.reduce.call(
intString,
(a, intChar) => a + (intChar ** intLength),
0 // initial value of accumulator a
);
console.log(result);
If I have the following:
var a = 5;
How can I make it so that this is converted into
[0,1,2,3,4]
I know it's a very simple question but I have never seen it done and cannot think of a simple way of doing it.
You can just use a loop and do:
var a = 5;
var arr = [];
for(var i=0; i<a; i++) {
arr.push(i);
}
As others have stated in their answers,
Array direct assignment is even faster than Push
Having used jsperf, that appears to be incorrect for Chrome/Firefox. See below:
http://jsperf.com/js-array232
From this, I would use push as stated in my answer above.
Array direct assignment is even faster than Push :
var arr=[],n=5;//N is 5 in your case
while(n--)
{
arr[n]=n;
};
Performance proof for Internet Explorer:
http://jsperf.com/js-array232/4
The easy, obvious solution is just to use a for loop,
var a = 5, arr = [];
for (var i=0;i<a;arr.push(i++));
arr now contains your ascending array of length a (5).
Or use direct assignment,
var a = 5, arr = [];
while (a--) arr[a] = a;
for a slightly shorter, albeit slower, algorithm.
In the following code sample i get a strange behavior
var data = ['xxx', 'yyy'];
for (var i in data)
{
var a = i;
var b = data[i];
}
The two first iterations works just fine. I get index "0" and "1" in i, but then it loops one extra time and now the i is "sum". Is this by design or what is this extra iteration used for? The result in my case is always empty and it messes up my code. Is there a way to not do his extra loop?
BR
Andreas
It looks like you (or some other code you've included) have added extra properties onto the Array prototype. What you should be doing is checking to see whether the object you're iterating over actually has that property on itself, not on its prototype:
for (i in data) {
if (data.hasOwnProperty(i)) {
a = i;
b = data[i];
}
}
That said, you should never use for .. in on arrays. Use a regular for loop.
See here for more information: http://yuiblog.com/blog/2006/09/26/for-in-intrigue/
You are looping through an Array, not through an Object. For arrays it's better to use:
for (var i=0; i<data.length; i=i+1){
/* ... */
}
In your loop every property of the Array object is taken into account. That makes the for ... in loop for array less predictable. In your case it looks like sum is a property (method) that's added to Array.prototype elsewhere in your code.
There are more ways to loop through arrays. See for example this SO-question, or this one
Just for fun, a more esoteric way to loop an array:
Array.prototype.loop = function(fn){
var t = this;
return (function loop(fn,i){
return i ? loop(fn,i-1).concat(fn(t[i-1])) : [];
}(fn,t.length));
}
//e.g.
//add 1 to every value
var a = [1,2,3,4,5].loop(function(val){return val+1;});
alert(a); //=> [2,3,4,5,6]
//show every value in console
var b = [1,2,3,4,5].loop(function(val){return console.log(val), val;});
Here's a way to safely iterate.
var data = ['xxx', 'yyy'];
for (var i = 0; i < data.length; i++)
{
var a = i;
var b = data[i];
}
What you are getting is an method coming from extending the Array object, I guess you are using some library where is something like
Array.prototype.sum = function () {...};
Perhaps setting data like this would work better: var data = {0:'xxx', 1:'yyy'};
First of all data is an object. Try to add console.log(a); and console.log(b); inside your loop and you'll see.