I'm new to javascript.
I'm trying to find the index of a specific element in an array. I read about that I can use findIndex to loop through an array. But it seems that findIndex only accept three arguments: element, index and array. What if I want change the object that is used to be compared.
For example, I want for find the index of string 'b' in array ['a','b','c'],
var position = ['a','b','c'].findIndex(function(element, index, array){return element==='b'})
but how do I pass 'b' as parameters that I can change to callback function
Thanks
What about indexOf function? You just have to pass one argument, as searched element.
let arr = ['a','b','c'];
console.log(arr.indexOf('b'));
You can define the wanted character from the outside context inside the callback function:
var wantedChar = 'c';
var position = ['a','b','c'].findIndex(function(element, index, array){return element===wantedChar})
console.log(position);
By doing so, you can wrap all that up in a function:
var findPos = function(arr, char){
return arr.findIndex(function(element, index, array){return element===char});
}
console.log(findPos(['a','b','c'], 'c'));
Note: as already suggested, it makes more sense to use indexOf when just comparing strings. The findIndexfunction in combination with a custom callback is there for more sophisticated search, e.g. when dealing with complex structured objects.
function getPosition(){
var position = ["a","b","c"];
var a = position.indexOf("b");
document.getElementById("demo").innerHTML = a;
}
<button onclick="getPosition()">button</button>
<p id="demo"></p>
Related
Are there any substantial reasons why modifying Array.push() to return the object pushed rather than the length of the new array might be a bad idea?
I don't know if this has already been proposed or asked before; Google searches returned only a myriad number of questions related to the current functionality of Array.push().
Here's an example implementation of this functionality, feel free to correct it:
;(function() {
var _push = Array.prototype.push;
Array.prototype.push = function() {
return this[_push.apply(this, arguments) - 1];
}
}());
You would then be able to do something like this:
var someArray = [],
value = "hello world";
function someFunction(value, obj) {
obj["someKey"] = value;
}
someFunction(value, someArray.push({}));
Where someFunction modifies the object passed in as the second parameter, for example. Now the contents of someArray are [{"someKey": "hello world"}].
Are there any drawbacks to this approach?
See my detailed answer here
TLDR;
You can get the return value of the mutated array, when you instead add an element using array.concat[].
concat is a way of "adding" or "joining" two arrays together. The awesome thing about this method, is that it has a return value of the resultant array, so it can be chained.
newArray = oldArray.concat[newItem];
This also allows you to chain functions together
updatedArray = oldArray.filter((item) => {
item.id !== updatedItem.id).concat[updatedItem]};
Where item = {id: someID, value: someUpdatedValue}
The main thing to notice is, that you need to pass an array to concat.
So make sure that you put your value to be "pushed" inside a couple of square brackets, and you're good to go.
This will give you the functionality you expected from push()
You can use the + operator to "add" two arrays together, or by passing the arrays to join as parameters to concat().
let arrayAB = arrayA + arrayB;
let arrayCD = concat(arrayC, arrayD);
Note that by using the concat method, you can take advantage of "chaining" commands before and after concat.
Are there any substantial reasons why modifying Array.push() to return the object pushed rather than the length of the new array might be a bad idea?
Of course there is one: Other code will expect Array::push to behave as defined in the specification, i.e. to return the new length. And other developers will find your code incomprehensible if you did redefine builtin functions to behave unexpectedly.
At least choose a different name for the method.
You would then be able to do something like this: someFunction(value, someArray.push({}));
Uh, what? Yeah, my second point already strikes :-)
However, even if you didn't use push this does not get across what you want to do. The composition that you should express is "add an object which consist of a key and a value to an array". With a more functional style, let someFunction return this object, and you can write
var someArray = [],
value = "hello world";
function someFunction(value, obj) {
obj["someKey"] = value;
return obj;
}
someArray.push(someFunction(value, {}));
Just as a historical note -- There was an older version of JavaScript -- JavaScript version 1.2 -- that handled a number of array functions quite differently.
In particular to this question, Array.push did return the item, not the length of the array.
That said, 1.2 has been not been used for decades now -- but some very old references might still refer to this behavior.
http://web.archive.org/web/20010408055419/developer.netscape.com/docs/manuals/communicator/jsguide/js1_2.htm
By the coming of ES6, it is recommended to extend array class in the proper way , then , override push method :
class XArray extends Array {
push() {
super.push(...arguments);
return (arguments.length === 1) ? arguments[0] : arguments;
}
}
//---- Application
let list = [1, 3, 7,5];
list = new XArray(...list);
console.log(
'Push one item : ',list.push(4)
);
console.log(
'Push multi-items :', list.push(-9, 2)
);
console.log(
'Check length :' , list.length
)
Method push() returns the last element added, which makes it very inconvenient when creating short functions/reducers. Also, push() - is a rather archaic stuff in JS. On ahother hand we have spread operator [...] which is faster and does what you needs: it exactly returns an array.
// to concat arrays
const a = [1,2,3];
const b = [...a, 4, 5];
console.log(b) // [1, 2, 3, 4, 5];
// to concat and get a length
const arrA = [1,2,3,4,5];
const arrB = [6,7,8];
console.log([0, ...arrA, ...arrB, 9].length); // 10
// to reduce
const arr = ["red", "green", "blue"];
const liArr = arr.reduce( (acc,cur) => [...acc, `<li style='color:${cur}'>${cur}</li>`],[]);
console.log(liArr);
//[ "<li style='color:red'>red</li>",
//"<li style='color:green'>green</li>",
//"<li style='color:blue'>blue</li>" ]
var arr = [];
var element = Math.random();
assert(element === arr[arr.push(element)-1]);
How about doing someArray[someArray.length]={} instead of someArray.push({})? The value of an assignment is the value being assigned.
var someArray = [],
value = "hello world";
function someFunction(value, obj) {
obj["someKey"] = value;
}
someFunction(value, someArray[someArray.length]={});
console.log(someArray)
var s = [23, 65, 98, 5];
Array.prototype.myMap = function (callback) {
var newArray = [];
this.forEach(function (a) {
return newArray.push(callback(a));
});
return newArray;
};
var new_s = s.myMap(function (item) {
return item * 2;
});
myMap is a function we have defined that has a param called callback
inside myMap is a forEach that executes a function once on each array element. It's this line I don't understand
return newArray.push(callback(a));
so push() to newArray
MDN push(): - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push
But push() accepts only one parameter. So why do we have .push(callback(a)) why not just .push(a)?
But push() accepts only one parameter. So why do we have .push(callback(a))
The return value of callback(a) is only one parameter.
why not just .push(a)?
The point of mapping is to take an array of data and create a new array where each item is transformed in some way.
If you didn't pass a through the callback function, it wouldn't be transformed, and you'd just be making a shallow copy.
The syntax push(callback(a)) denotes that:
push() itself accepts one param, a callback, which...
...is automatically passed one param (the iterative array item)
callback(a) is indeed one object, or parameter in this case. The push will push the result of the call to callback(a) to the array. It's effectively the same as this:
var item = callback(a);
newArray.push(item);
But you're pushing the result of callback directly, rather than storing it in a variable first.
I am trying to understand how to implement the map method (rather than using a for loop) to check a string for palindromes and return boolean values for whether the mapped array elements reversed are the same as the original array elements. I cannot seem to understand the syntax of the map method. How do I get the map to function on each element in the original array? What is the value? Here is my working code, which is only logging a value of undefined:
function palindromeChecker(string) {
var myString = string.toLowerCase();
var myArray = myString.split(" ");
var newArray = myArray.map(function (item) {
item.split("").reverse().join("");
return newArray === myArray;
});
}
console.log(palindromeChecker("What pop did dad Drink today"));
Here is a link to the fiddle:
https://jsfiddle.net/minditorrey/3s6uqxrh/1/
There is one related question here:
Javascript array map method callback parameters
but it doesn't answer my confusion about the syntax of the map method when using it to perform a function on an array of strings.
The map method will literally 'map' a function call onto each element in the array, take this as a simple example of increasing the value of each integer in an array by 1:
var items = [1,2,3];
items.map(function(item) {
return item + 1;
});
// returns [2,3,4]
In your case, you are trying to use map to accept or reject a string if it's a palindrome, so a simple implementation might be:
var items = ['mum', 'dad', 'brother'];
items.map(function(item) {
return item.split('').reverse().join('') === item;
});
// returns [true, true, false]
I'm not 100% sure of your reasons for using map, because if you were trying to just filter the array and remove the strings that aren't palindromes, you should probably use the filter method instead, which works in the same way, but would remove any that return false:
var items = ['mum', 'dad', 'brother'];
items.filter(function(item) {
return item.split('').reverse().join('') === item;
});
// returns ['mum', dad']
In your case you are splitting a string first to get your array of characters; you may also want to make that string lower case and remove punctuation, so an implementation might be:
var string = 'I live at home with my Mum, my Dad and my Brother!';
var items = string.toLowerCase().replace(/[^a-z0-9-\s]+/, '').split(' ');
items.filter(function(item) {
return item.split('').reverse().join('') === item;
});
// returns ['i', 'mum', dad']
As mentioned in one of the comments on your question, you need to ensure you return a value from your function if you are using a separate function to perform the check, so this is how your function should look:
function checkPalindromes(string) {
var items = string.toLowerCase().replace(/[^a-z0-9-\s]+/, '').split(' ');
items.filter(function(item) {
return item.split('').reverse().join('') === item;
});
return items;
}
And you would call it using:
checkPalindromes('I live at home with my Mum, my Dad and my Brother!'); // ['i', 'mum', 'dad']
try something like this:
let str = 'hello';
let tab = [...str];
tab.map((x)=> {
console.log("|"+x+"|");
return x;
})
newArray should include reversed version of theall items in myArray. After that, newArray should be reversed and joined with space in order to get the reversed version of the input string.
Here is the code:
function palindromeChecker(string) {
var myString = string.toLowerCase();
var myArray = myString.split(" ");
var newArray = myArray.map(function (item) {
return item.split("").reverse().join("");
});
console.log(newArray);
return newArray.reverse().join(" ") === string;
}
console.log(palindromeChecker("dad did what"));
Javascript map method on array of string elements by using split() function.
let str = 'hello';
str.split('').map((x)=> {
console.log("|"+x+"|");
return x;
})
Map is a higher-order function available in ES5. I think your newArraywill contain an array of boolean values.
In essence, map will iterate over every value in your array and apply the function. The return value will be the new value in the array. You can also use map and save the information you need somewhere else, and ignore the result of course.
var arr = [1,2,3,4];
var newArray = arr.map(function(i) {
return i * 2;
});
//newArray = [2,4,6,8]
The map function in javascript (and pretty much in any language) is a great little function that allows you to call a function on each of the items on a list, and thus changing the list itself.
The (anonymous) function you're passing as an argument accepts an argument itself, which is filled by an item of the list it is working on, each time it is called.
So for a list [1,2,3,4], the function
function(item) { return item + 1 }, would give you a list of [2,3,4,5] for a result. The function you passed to $.map() is run over each element of the list, and thus changing the list.
So for your code: in the function you're passing as an argument to $.map(), you're returning whether the old and new array are equal (which is false btw). So since you're returning a boolean value, the list you'll end up with is a list of bools.
What I think you want to do, is extract the newArray == myArray from the function you're passing to $.map(), and putting it after your $.map() call.
Then inside the function you're passing to $.map(), return the item you're splitting and whatnot, so your newArray will be an array of strings like myArray.
Apart from a few minor mistakes in your code, such as scope issues (you're referencing the "newArray" and "myArray" outside of the function in which they where defined, and therefore, getting "undefined")..
The main issue you had is that you addressed the ENTIRE array inside the map function, while the whole concept is breaking things down to single elements (and then the function collects everything back to an array for you).
I've used the "filter" function in my example, because it works in a similar manner and I felt that it does what you wanted, but you can change the "filter" to a "map" and see what happends.
Cheers :)
HTML:
<body>
<p id="bla">
BLA
</p>
<p id="bla2">
BLA2
</p>
</body>
Javascript:
function palindromeChecker(string) {
var myString = string.toLowerCase();
var myArray = myString.split(" ");
var newArray = myArray.filter(function (item) {
var reversedItem = item.split('').reverse().join('');
return item == reversedItem;
});
document.getElementById("bla").innerHTML = myArray;
document.getElementById("bla2").innerHTML = newArray;
}
palindromeChecker("What pop did dad Drink today");
Thanks for your input, all. This is the code I ended up with. I fixed the scope issues in the original post. My main problem was understanding the syntax of the map method. In particular, I could not understand from other online resources how to determine the value in the callback function. So, with much help from above I have placed the map method inside the palindromeChecker, and done all of the work on the array inside the map function.
var palindromeChecker = function(string) {
var newString = string.toLowerCase().split(' ');
newString.map(function(item) {
console.log(item.split('').reverse().join('') === item);
});
};
palindromeChecker("What pop did dad drink today");
//Returns false, true, true, true, false, false
I am trying to set up an array in jQuery and I then need to do a for loop on it. But it seems that I cant use an associative array for some reason?
var items = new Array();
items['foo'] = 123456;
items['bar'] = 789012;
items['baz'] = 345678;
items['bat'] = 901234;
alert(items.length);
This is just a test, but it return 0?
You can't make associative array in JavaScript like what you want, instead you can use Object.
For example:
var items = {
foo : 123456,
bar : 789012,
baz : 345678,
bat : 901234
}
And to calculate the length you can do:
var getObjectSize = function(obj) {
var len = 0, key;
for (key in obj) {
if (obj.hasOwnProperty(key)) len++;
}
return len;
};
Use: getObjectSize(items); // output: 4
For more see here.
Another one is:
Object.keys(items).length;
But not supported by all browsers.
var items = new Array();
items['foo'] = 123456;
The problem lies in the very first line. You believe that you are adding an item to the array at the index foo, but you are actually adding a property to the items variable with a key foo and value 123456. If you were to type items.foo it would give you back your 123456.
The problem with this approach is that adding a property to an array does not magically increase it's length.
If you want to have non-numeric indexes, you need to use an object instead of an array:
var items = {
foo: 123456,
bar: 789012,
baz: 345678,
bat: 901234
};
Another approach might be to set up two different arrays, which you construct in parallel:
var items = [], items2 = [];
items.push('foo');
items2.push(123456);
// etc.
alert(items2.length);
The efficiency of this approach depends on how you'll use it. If you're only going to loop through the list of items and do something to each of them, this approach may be more efficient. But if you need to use it like an associative array (items['foo']), then you're better off building an object.
The .length property returns the highest numerical index of the array. Thus, in your case, there is no numerical index and it returns 0. Try
items[98] = "something";
items.length will be 98..! Use the .length property with caution, and if you also want to count the non-numerical indici, loop over the Object (an Array is also an Object) and count its ownProperties.
I have an array with random count of elements, for example:
var array = [1, 2];
And I want to execute some function with the next parameters:
functionName(SOME_CONST, array[0], array[1])
What is the best way to do this, considering that array could have a different number of parameters?
Have a look at https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply for details on how to use the Function.prototype.apply method.
So long as you want to use all of the items in your array as arguments in the function that you are calling, you can use:
function some_method(a, b, c) {}
var array = [1,2];
some_method.apply(this, ['SOME_CONST'].concat(array));
which will result in calling some_method with a being the 'SOME_CONST' and b and c being the first two elements in the array. If you had more elements in the array, they would come next in the arguments list in the some_method function.
You can just call the function and pass in the array itself instead of it's elements like this
function functionName(SOME_CONST, myArray){
//myArray contains the same elemnts here too
}
then you can call the function like this
var myArray = [1,2];
functionName(CONST_VAL,myArray);
The simplest solution would be to pass the whole array to the function and have the function iterate over it. This would allow for a variable length array.
functionName(SOME_CONST, array) {
for (var ii = 0, len = array.length; ii < len; ii++) {
// do something.
}
}
Use .apply, and array join, i mean create new array, let the SOME_CONST be the first element and join the other array which you already have.
You can do like this,
var array = [1, 2];
functionName.apply(thisObj || window, [SOME_CONST].join(array));
function functionName(a, b, c){
//a is SOME_CONST, b is 1 and c is 2
}
thisObj is the scope/context of the function which you are calling. If you dont have a thisObj just pass window object