I have a Javascript function called reverseArray that takes an array as the argument and returns a new array which has the same values as the input array in reverse order. I want to create a function called reverseArryInPlace which would change the value of the input array to the reverse order.
function reverseArray(inputArray) {
var outputArray = [];
for (var i = inputArray.length - 1; i >= 0; i--)
outputArray.push(inputArray[i]);
return outputArray;
}
function reverseArrayInPlace(inPlaceInputArray) {
inPlaceInputArray = reverseArray(inPlaceInputArray);
console.log('Inside reverseArrayInPlace: ' + inPlaceInputArray);
return inPlaceInputArray;
}
var arrayValue = [1, 2, 3, 4, 5];
reverseArrayInPlace(arrayValue);
console.log('Outside reverseArrayInPlace: ' + arrayValue);
// Expected Value: [5, 4, 3, 2, 1]
Here is the result I get when I execute this chunk of code:
Inside reverseArrayInPlace: 5,4,3,2,1
Outside reverseArrayInPlace: 1,2,3,4,5
Within the reverseArrayInPlace function the arrayValue variable has been reversed as expected. Why is it that when I reference the same variable outside the reverseArrayInPlace function, it is back to the original order?
If you want to reverse it in place, you have to reverse it in place.
function reverseArrayInPlace(array) {
for (let i = 0, j = array.length - 1; i < j; i++, j--)
[array[i], array[j]] = [array[j], array[i]];
}
const a = [1,2,3,4,5];
reverseArrayInPlace(a);
console.log(a);
The underlying problem here is that primitives are passed by value in JavaScript. See the following question for details:
Javascript by reference vs. by value
As a simple example, here is a function that attempts to mutate a string that was passed to it:
var outsideValue = 'foo'
function mutate(value) {
value = 'fish'
}
mutate(outsideValue);
console.log(outsideValue);
However, the console output is foo.
This happens because the value variable within the mutate function is a variable that has a reference to outsideValue when the function is initially invoked. When it is assigned the new value within the function body, it merely changes the value variable to reference a new string. As a result, the outsideValue is untouched.
Check this answer for an example that reverses in place:
https://stackoverflow.com/a/43486686/249933
Notice, that it does not re-assign the function argument.
As others have said, arrays are objects so they're passed by reference. You have to modify the original array, not create a new one.
So here's another version of reverseInPlace, it uses shift to remove the last element from the array and splice to insert it in the new location:
function reverseInPlace(arr) {
var i = arr.length;
while (i--) {
arr.splice(i, 0, arr.shift());
}
}
var arr = [1,2,3,4,5];
console.log('Before: ' + arr.join());
reverseInPlace(arr);
console.log('After: ' + arr.join());
For some fun, you can also leverage sort:
NB: this only works in some browsers, it's dependent on the built-in sort algorithm which is implementation dependent.
function reverseInPlace(arr) {
arr.sort(() => 1);
}
var arr = [47, 95, 80, 62, 8, 34, 31, 17, 62, 17, 85, 72, 51, 20, 68, 60, 30, 84, 7, 34];
console.log('Before: ' + arr.join());
reverseInPlace(arr);
console.log('After : ' + arr.join());
function reverseArray(inputArray) {
var outputArray = [];
for (var i = inputArray.length - 1; i >= 0; i--)
outputArray.push(inputArray[i]);
return outputArray;
}
function reverseArrayInPlace(inPlaceInputArray) {
inPlaceInputArray = reverseArray(inPlaceInputArray);
console.log('Inside reverseArrayInPlace: ' + inPlaceInputArray);
return inPlaceInputArray;
}
var arrayValue = [1, 2, 3, 4, 5];
**arrayValue = reverseArrayInPlace(arrayValue);**
alert('Outside reverseArrayInPlace: ' + arrayValue);
// Expected Value: [5, 4, 3, 2, 1]
//
your code is correct your just need to replace one line and write
arrayValue = reverseArrayInPlace(arrayValue);
instead of
reverseArrayInPlace(arrayValue);
Then arratValue will print expected values
Related
I have a function which takes an array and further arguments like this:
function arrayandmore([1, 2, 3], 2, 3)
I need to return the array ([1, 2, 3]) without those elements which equals the arguments coming behind the array. So in this case, the returned array would be:
([1]).
One of my approaches is:
function destroyer(arr) {
var args = Array.from(arguments);
var i = 0;
while (i < args.length) {
var result = args[0].filter(word => word !== args[i]);
i++;
}
console.log(result);
}
destroyer([1, 1, 3, 4], 1, 3);
Console returns:
[ 1, 1, 4 ]
I don't understand, why it returns one too - I don't understand, why it does not work.
It is the same with using splice.
function destroyer(arr) {
var args = Array.from(arguments);
var quant = args.length - 1;
for (var i = 1; i <= quant; i++) {
if (arr.indexOf(args[i]) !== -1) {
arr = arr.splice(arr.indexOf(args[i]));
}
console.log(arr);
}
}
destroyer([1, 1, 3, 4], 1, 3);
I think, both ways should work. But I don't figure out why they don't.
Your while won't work because result is being overwritten in every loop. So, it only ever removes the last parameter to the destroyer function
You can use the rest parameter syntax to separate the array and the items to be removed.
Then use filter and includes like this:
function destroyer(arr, ...toRemove) {
return arr.filter(a => !toRemove.includes(a))
}
console.log(destroyer([1, 1, 3, 4, 5], 1, 3))
I have 10 different arrays. Each array has different numbers.
array1 = [1,2,3,4,5]
array2 = [6,7,8,9,10]
...
array 10 = [51,52,53,54]
let's say I pass in 7. Then I want to know which array it is from and want to return array number. So in this case it is going to be 2.
Should I write a switch statement for each array? Appreciate it in javascript.
try:
var arrays = [array1, array2, ..., array10];
for(var i=0; i<arrays.length; ++i) {
if (arrays[i].indexOf(value) != -1) {
console.log('found in array' + (i+1));
}
}
You cannot directly retrieve the name of array.The reason is this variable is only storing a reference to the object.
Instead you can have a key inside the same array which represent its name. Then indexOf can be used to find the array which contain the number , & if it is so, then get the array name
var array1 = [1,2,3,4,5];
array1.name ="array1";
var array2 = [6,7,8,9,10];
array2.name ="array2";
var array10 = [51,52,53,54]
array10.name ="array10";
var parArray = [array1,array2,array10]
function _getArrayName(number){
for(var o=0;o<parArray.length;o++){
var _tem = parArray[o];
if(parArray[o].indexOf(number) !==-1){
console.log(parArray[o].name);
}
}
}
_getArrayName(6) //prints array2
jsfiddle
One fast method should be using hash tables or as i would like to call LUT. Accordingly this job boils down to a single liner as follows;
var arrs = {
arr1 : [1,2,3,4,5],
arr2 : [6,7,8,9,10],
arr3 : [12,14,16,17],
arr4 : [21,23,24,25,27,20],
arr5 : [31,34,35,39],
arr6 : [45,46,44],
arr7 : [58,59],
arr8 : [66,67,69,61],
arr9 : [72,73,75,79,71],
arr0 : [81,85,98,99,90,80]
},
lut = Object.keys(arrs).reduce((p,c) => {arrs[c].forEach(n => p[n]=c); return p},{}),
findar = n => lut[n];
document.write("<pre>" + findar(12) + "</pre>");
One way to do this is have the arrays in an object and iterate over the keys/values. This method doesn't presume the arrays (and therefore their names) are in sequential order.
Note: this will always return a the first match from the function and terminate the search.
var obj = {
array1: [1, 2, 3, 4, 5],
array2: [6, 7, 8, 9, 10],
array3: [51, 52, 53, 54],
array4: [51, 52, 53, 54, 7]
}
function finder(obj, test) {
var keys = Object.keys(obj);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (obj[key].indexOf(test) > -1) {
return key.match(/\d+/)[0];
}
}
return false;
}
finder(obj, 7); // '2'
DEMO
If you want to find all instances of a value in all arrays the function needs to be altered slightly.
function finder(obj, test) {
var keys = Object.keys(obj);
var out = [];
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (obj[key].indexOf(test) > -1) {
out.push(key.match(/\d+/)[0]);
}
}
return out;
}
finder(obj, 7); // ['2', '4']
DEMO
I am needing to find the correct way to have javascript loop through an array, find all numbers that are divisible by 3, and push those numbers into a new array.
Here is what I have so far..
var array = [],
threes = [];
function loveTheThrees(array) {
for (i = 0, len = array.length; i < len; i++) {
threes = array.push(i % 3);
}
return threes;
}
So if we pass through an array of [1, 2, 3, 4, 5, 6] through the function, it would push out the numbers 3 and 6 into the "threes" array. Hopefully this makes sense.
You can use Array#filter for this task.
filter() calls a provided callback function once for each element in an array, and constructs a new array of all the values for which callback returns a true value or a value that coerces to true. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values. Array elements which do not pass the callback test are simply skipped, and are not included in the new array.
function loveTheThrees(array) {
return array.filter(function (a) {
return !(a % 3);
});
}
document.write('<pre>' + JSON.stringify(loveTheThrees([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), 0, 4) + '</pre>');
console.log([1, 2, 3, 4, 5, 6, 7].filter(function(a){return a%3===0;}));
Array.filter() iterates over array and move current object to another array if callback returns true. In this case I have written a callback which returns true if it is divisible by three so only those items will be added to different array
var array = [],
three = [];
function loveTheThrees(array) {
for (i = 0, len = array.length; i < len; i++) {
if(array[i] % 3 == 0){
three.push(array[i]);
}
}
return three;
}
Using Filter like suggested by Nina is defiantly the better way to do this. However Im assuming you are a beginner and may not understand callbacks yet, In this case this function will work:
function loveTheThrees(collection){
var newArray = []
for (var i =0; i< collection.length;i++){
if (myArray[i] % 3 === 0){
newArray.push(collection[i])
}
}
return newArray;
}
loveTheThrees=(arr)=>arr.filter(el=>Boolean(parseFloat(el)) && isFinite(el) && !Boolean(el%3))
es6 version + skipping non numbers
loveTheThrees([null,undefined,'haha',100,3,6])
Result: [3,6]
Check if the number is divisible by 3 if so then add it to array. Try this
function loveTheThrees(array) {
for (i = 0, len = array.length; i < len; i++) {
if(array[i] % 3 == 0){
three.push(array[I]);
}
}
var originalArray = [1, 2, 3, 4, 5, 6, 7, 8, 9];
function loveTheThrees(array1) {
var threes = [];
for (var i = 0; i < array1.length; i++) {
if (array1[i] % 3 === 0) {
threes.push(array1[i]);
}
}
return threes;
}
loveTheThrees(originalArray);
In ES6:
const arr = [1, 33, 54, 30, 11, 203, 323, 100, 9];
// This single line function allow you to do it:
const isDivisibleBy3 = arr => arr.filter(val => val % 3 == 0);
console.log(isDivisibleBy3(arr));
// The console output is [ 33, 54, 30, 9 ]
I'm calling a function inside of my script main
function func(a) {
var idx;
a=a.sort();
for (idx = 0; idx < a.length + 1; idx += 1) {
if (a.indexOf(idx) === -1) {
return idx;
}
}
return 0;
}
var array = [2,1,0];
var b = func(array);
console.log(array);
The function argument (a) is an array that is being passed to the func function.
When I try to access the array in the main body of the program after calling this function it's sorted.
Does node.js link the scope between the array passed to the 'func' function and the array that was passed to it?
After calling this code, array is sorted. Why is that?
This is even true if I declare a new variable, b inside the function scope.
function func(a) {
var idx, b;
b = a;
b = b.sort();
for (idx = 0; idx < a.length + 1; idx += 1) {
if (a.indexOf(idx) === -1) {
return idx;
}
}
return 0;
}
var array = [2,1,0];
var b = func(array);
console.log(array);
The above code has the same issue.
It's not a scope leak but a twofold reason for what is happening:
because sort directly modifies the array it is applied on (while also returning it)
functions in JavaScript work with pass by reference for objects
For reason #1 look at this simple example:
var a = [3,4,1,2];
a; // [3, 4, 1, 2]
a.sort(); // [1, 2, 3, 4]
a; // [1, 2, 3, 4]
As you can see it returns the sorted array which is nothing more than the array itself that has been modified by the sort.
For reason #2 look at this simple example:
function foo(a) { a.push('hello'); }
var arr = [1,2,3,4];
arr; // [1, 2, 3, 4]
foo(arr); // undefined
arr; // [1, 2, 3, 4, "hello"]
So combining those two reasons you can see that you are passing a reference to the array into the function and then directly modifying it with a sort.
If you want to do the same thing without modifying the original array you could use Array.prototype.slice() which returns a shallow copy of the original array.
var a = [3,4,1,2];
var arr = a.slice();
a; // [3, 4, 1, 2]
arr; // [3, 4, 1, 2]
arr.sort(); // [1, 2, 3, 4]
arr; // [1, 2, 3, 4]
a; // [3, 4, 1, 2]
I'm trying to loop through an array in order to group and count totals.
For example:
var farm = [['Cats', 3], ['Cats', 4], ['Mice', 2], ['Dogs', 5]];
I would like to go through and first see 'Cats', then add all the cat values up, then repeat the process for other unique categories.
The final output would be:
Cats (7)
Mice (2)
Dogs (5)
Currently, I'm trying to accomplish it this way, but I'm obviously making a rookie mistake somewhere.
var farm = [];
farm.push(['Cats', 3], ['Cats', 4], ['Mice', 2], ['Dogs', 5]);
var animalCounter = function(array){
var list = '';
for(var i = 0; i<array.length; i++){
var animalID = array[i][0];
var animalCount = 0;
for (var x; x<array.length; x++){
if(animalID == array[x][0]){
animalCount += array[x][0] - 1;
}
list += animalID + " (" + animalCount + ")\n";
}
}
alert(list);
}
animalCounter(farm);
use an object to add similar animals together
var farm = [];
farm.push(['Cats', 3], ['Cats', 4], ['Mice', 2], ['Dogs', 5]);
var o = {};
for (var i=farm.length; i--;) {
var key = farm[i][0],
val = farm[i][1];
o[key] = key in o ? o[key] + val : val;
}
FIDDLE
Then it's easy to create the list
for (var key in o) {
list += key + " (" + o[key] + ")\n";
}
FIDDLE
You're missing an outer layer of brackets:
var farm = [['Cats', 3], ['Cats', 4], ['Mice', 2], ['Dogs', 5]];
What you had will end up being the same as
var farm = ['Dogs', 5];
The comma operator does strange things, especially in a var statement because , also separates individual variable declarations and initializations.
I'd probably do it a bit differently:
var farm = [];
farm.push(['Cats', 3], ['Cats', 4], ['Mice', 2], ['Dogs', 5]);
var animalCounter = function(array){
var animalObject = {};
for(var i = 0; i<array.length; i++){
var animalID = array[i][0];
var animalCount = array[i][1];
if(animalObject[animalID]) {
animalObject[animalID] += animalCount;
} else {
animalObject[animalID] = animalCount;
}
}
return animalObject;
}
The first function, animalCounter, creates an object that maps animal names to the numbers in the array. So for your example, it will return an object that looks like this:
{ 'Cats': 7, 'Mice': 2, 'Dogs': 5 }
From there, once you have the object, it's trivial to create a string to output this data in whatever format you like:
var counter = animalCounter(farm);
var list = '';
for(var key in counter) {
list += key + ': ' + counter[key] + ', ';
}
console.log(list); //=> Cats: 7, Mice: 2, Dogs: 5,
The reason your initial function didn't work is because it didn't take into account that there might be more than one instance of the same animal in your array. If your original array was [['Cats', 7], ['Mice', 2], ['Dogs', 5]] it would have been fine, but because your Cats entry was split into ['Cats', 4], ['Cats', 3], your original code saw that as two distinct animals. Notice in my function:
if(animalObject[animalID]) {
animalObject[animalID] += animalCount;
} else {
animalObject[animalID] = animalCount;
}
The code checks to see if the animal is already stored in the new object, and if it is, increments the count, rather than creating a new counter from 0. This way it deals with any duplicates.
I see three problems:
setting animalCounter equal to the number of animals - the new number of animals replaces whatever might already have been stored in animalCounter, so nothing is added up here
creating the animalCounter variable within the loop - if var animalCount is inside the loop, then you actually have a completely new variable for each element of the array
using a single variable for all the types of animals
Instead, try this:
var farm = [];
farm.push(['Cats', 3], ['Cats', 4], ['Mice', 2], ['Dogs', 5]);
var animalCounter = function (array) {
var list = '',
catsCount = 0,
miceCount = 0,
dogsCount = 0;
for (var i = 0; i < array.length; i++) {
var animalID = array[i][0];
var animalCount = array[i][1];
if (animalID === 'Cats') {
catsCount += animalCount;
} else if (animalID === 'Mice') {
miceCount += animalCount;
} else if (animalID === 'Dogs') {
dogsCount += animalCount;
}
}
list = 'Cats(' + catsCount + ') Mice(' + miceCount + ') Dogs(' + dogsCount + ')';
alert(list);
}
animalCounter(farm);
There are separate variables for each type of animal, and the value in the array is added onto the correct counter variable.
Or, for a more organized solution:
var farm = []; farm.push(['Cats', 3], ['Cats', 4], ['Mice', 2],
['Dogs', 5]);
var animalCounter = function (array) {
var list = '',
animalCounters = {};
for (var i = 0; i < array.length; i++) {
var animalID = array[i][0];
var animalCount = array[i][1];
animalCounters[animalID] = (animalCounters[animalID] || 0) + animalCount;
}
for (var id in animalCounters) {
list += id + " (" + animalCounters[id] + ")\n";
}
alert(list);
} animalCounter(farm);
In this code, the animalCounters variable is an object. JavaScript objects act like associative arrays, which lets us use the animal ID string as a "key" to an integer that is the animal sum. Each type of animal is a property of the animalCounters object, with the sum for that type of animal as its value.
I used some slightly obscure notation here, so I'll explain.
animalCounters[animalID]
This is just a different method of referring to properties of an object. In JavaScript, animalCounters.Cats and animalCounters["Cats"] access the same thing. But, if you don't know for sure that the type of animal will be Cats, you need "Cats" (or whatever other kind of animal) to be in a variable. The animalCounters["Cats"] notation takes a string, so you can say this and it will work:
var animalID = "Dogs";
alert(animalCounters[animalID);// returns animalCounters.Dogs
animalCounters[animalID] = (animalCounters[animalID] || 0) + animalCount;
Here, the (animalCounters[animalID] || 0) is saying that if animalCounters[animalID] already has a value, add that value to animalCount, otherwise add 0 to animalCount. This is necessary because if you try to add animalCounters[animalID] to animalCount before animalCounters[animalID] has been set to anything, the addition won't work right.
Just for funsies... (not very practical)
var farm = [['Cats', 3], ['Cats', 4], ['Mice', 2], ['Dogs', 5]];
farm.reduce(function(a, b, i){
var r = (i==1 ? a.slice() : a),
j = r.indexOf(b[0]);
if(j >= 0){
r[j+1] += b[1];
return r;
} else return r.concat(b);
}).reduce(function(a, b, i){
return i%2 ? a+' ('+b+')' : a+'\n'+b;
});
Rough explanation:
Iterate over each element of farm reducing the 2D array to a flat array where every odd index is the "count" that corresponds to the previous element - taking note to check if the "key" in the even index already exists in the array (in which case update it's count respectively). The slice call is in there just to make sure that the original array is left unmodified. This results in an array looking like:
["Cats", 7, "Mice", 2, "Dogs", 5]
This new array is reduced once more, this time concatenating each element into a single string - formatting dependent on whether or not the current iteration has an odd or even index.
Array.reduce is one of those functions that isn't supported in older browsers (if that is important) but there's a polyfill available on the MDN site.
When you access the amount of animals of a certain kind you made a simple mistake:
animalCount += array[x][0] - 1;
farm[x][0] will always return the animal's name which is a string, so when trying to subtract 1 from it it will result in NaN (Not a Number).
Also the first for loop: for(var i; i<array.length; i++){ ... cycles through all the array slots even if they were already counted, so cats would be counted twice so instead of cats counted as 7 they would amount to 14.
You need to create a copy of array and take off the slots already counted. The tricky part is copying the array by value and so that any changes to Temp won't change farm (see Copying Arrays):
var farm = [];
farm.push(['Cats', 3], ['Cats', 4], ['Mice', 2], ['Dogs', 5]);
function countAnimals(array) {
var Temp = [];
var d = 0;
//This while loop copies the array
while (d < farm.length) {
var s = array[d].toString();
Temp.push(s.split(","));
d++;
}
var list = "";
var done = 0;
while (done < array.length) {
if(Temp[0][1] == "Done") {
Temp.shift();
} else {
var animalID = Temp[0][0];
var count = parseFloat(Temp[0][1]);
Temp.shift();
var i = 0;
while (i < Temp.length) {
if(Temp[i][0] == animalID) {
count = count + parseFloat(Temp[i][1]);
Temp[i][1] = "Done";
}
i++;
}
list = list + "\n" + animalID + "("+count+")";
}
done++;
}
alert(list);
}
countAnimals(farm);