Get objects position in array - javascript

I have an array players[]
function that gets certain object from such array by looking up its gameSocketId value and returns that object
getUserInfo : function(user)
{
var userInfo = Game.players.filter(function(e) {
return e.gameSocketId === user;
}).pop();
return userInfo;
}
so I store it in a variable like var user = getUserInfo(userId) How can I than find out what is the position of user in array of players[] knowing all info about it?

Use .findIndex:
getUserInfo : function(user)
{
var userInfoIndex = Game.players.findIndex(function(e) {
return e.gameSocketId === user;
});
return userInfoIndex;
}
Note that .findIndex, while fully specified is not included in most JS engines by default yet - there is a polyfill on mdn:
if (!Array.prototype.findIndex) {
Array.prototype.findIndex = function(predicate) {
if (this == null) {
throw new TypeError('Array.prototype.findIndex called on null or undefined');
}
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
}
var list = Object(this);
var length = list.length >>> 0;
var thisArg = arguments[1];
var value;
for (var i = 0; i < length; i++) {
value = list[i];
if (predicate.call(thisArg, value, i, list)) {
return i;
}
}
return -1;
};
}
This polyfill works on ES3 and ES5 browsers just fine :)
Of course, one can also use a normal for loop to do this which works all the way through ES1 - but then you don't get the fun syntax that conveys intent pretty clearly:
getUserInfo : function(user) {
for(var i = 0; i < Game.players.length; i++){
if(Game.players[i].gameSocketId === user) return i;
}
return -1;
}
We don't always have to be clever :)
Of course, we can also always be inefficient and just call .indexOf after obtaining the item using your original method.

The second param of Array.filter is the index for the current item. The below will still return you the userInfo that you originally specified plus you can use the index for whatever you want.
getUserInfo : function(user)
{
var playerIndex;
var userInfo = Game.players.filter(function(e, index) {
if (e.gameSocketId === user) {
playerIndex = index;
return true;
}
}).pop();
console.log(Game.players[playerIndex]) // <- the player that is also "user"
return userInfo;
}

How about using indexof()
getUserInfo : function(user){
var userInfo = Game.players.filter(function(e) {
return e.gameSocketId === user;
}).pop();
return userInfo;
}
// and later
var user = getUserInfo(userId)
console.log(Game.players.indexOf(user));

Related

custom assertion to compare arrays in Nightwatch.js does not work

I use nightwatch-cucumber that based on Nightwatch.js as testing framework to implement my automated end2end tests. So, I'm still new to 'JavaScript' and 'node.js'. Currently, I want to create a custom assertion in Nightwatch, but I get an error while test execution and I don't know what I'm doing wrong.
I get the following error:
Testing if arrays are equal. - Expected "true" but got: "[object Object]"
The assertion should compare different arrays in a given array, if they inherit equal values. So the array to give as parameter should like this var myArray[[1,2,3], [3,2,1]]. The assertion should compare all arrays in a given array with each other.
Here is my custom assertion:
var equals = require('array-equal');
var util = require('util');
exports.assertion = function(array, msg=null) {
this.message = msg || util.format('Testing if arrays are equal.');
this.expected = true;
this.pass = function(value) {
return value === this.expected;
};
this.value = function(result) {
return result.value;
};
this.command = function(callback) {
let params = [array];
let execute = function(array) {
for (var i = 0; i < array.length; i++) {
for (var k = i+1; k < array.length; k++) {
array[i].sort();
array[k].sort();
if (equals(array[i], array[k]) === false) {
return false;
}
}
}
return true;
};
let execcallback = result => {
if (callback) {
return callback.call(this, result);
}
};
return this.api.execute(execute, params, execcallback);
};
};
I use the PageObject pattern to write my tests.
Here is my code for executing my assertion:
module.exports = {
elements: {},
commands: [{
compareArrays() {
var list = [[1,2,3],[3,2,1]];
//I expect a passed assertion because the values in both arrays are equal
this.assert.arraysEqual(list);
return this.api;
}
}]
};
What are you doing in the loops?
Why don't place just
array[i].sort();
array[k].sort();
if (equals(array[i], array[k]) === false) {
return false;
}

return object if list<object> value is exists (Javascript, jquery grep/map)

I'm using grep and map functions to get the object if the value is exists in the list, but it does not work well.
I have a list customList and the customObject has the int id property and List value properties.
customobject[0].id
customObject[0].value[]
What I want is check if in the List the value 5 exists.
The function what I'm using is:
var gettedcustomObject = $.grep(customList, function (e) {
var result = e.Value.map(function (a) { return a === 5;});
return result;
});
What am I doing wrong and what is the correct implementation?
Note: 2x foreach could be a solution, but customList has more than 1000 objects with 10000 values. I think that slow down the proces.
This should do it.
var gettedcustomObject = customList.filter(function(v){
var ln = v.Value.length;
for(var i = 0; i < ln; i++){
if(v.Value[i] == 5){
return true;
}
}
return false;
// Or simply:
// return v.Value.indexOf(5) != -1;
});
This will work if v.Value is an array.
You should look at some: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some#Polyfill
Way faster than the other methods like filter, map or sort as it was designed for this.
//List to work against
var arr = [];
//Populate
while (arr.length < 9999999) {
arr.push(Math.random() * 999999)
}
//Set element to find
arr[10] = "test";
//Begin timing
var d = new Date().getTime();
//Run filter
console.log(arr.filter(function(a){return a === "test"}).length > 0);
//How long did it take
console.log("`filter` took:",new Date().getTime() - d,"ms")
//Begin timing
d = new Date().getTime();
//Run filter
console.log(arr.some(function(a){return a === "test"}));
//How long did it take
console.log("`some` took:",new Date().getTime() - d,"ms")
<script>
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some#Polyfill
// Production steps of ECMA-262, Edition 5, 15.4.4.17
// Reference: http://es5.github.io/#x15.4.4.17
if (!Array.prototype.some) {
Array.prototype.some = function(fun/*, thisArg*/) {
'use strict';
if (this == null) {
throw new TypeError('Array.prototype.some called on null or undefined');
}
if (typeof fun !== 'function') {
throw new TypeError();
}
var t = Object(this);
var len = t.length >>> 0;
var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
for (var i = 0; i < len; i++) {
if (i in t && fun.call(thisArg, t[i], i, t)) {
return true;
}
}
return false;
};
}
</script>
If your goal is to find the first object in the list that contains 5 in the Value property, then you're looking for Array#find and Array#indexOf:
var gettedcustomObject = customList.find(function(entry) {
return entry.Value.indexOf(5) != -1;
});
Note that Array#find was added relatively recently and so you may need a polyfill for it (which is trivial). MDN has one.
Or you could use Array#includes instead of indexOf, which will be in ES2017 and is also polyfillable:
var gettedcustomObject = customList.find(function(entry) {
return entry.Value.includes(5);
});
Live Example (using indexOf):
var customList = [
{
note: "I'm not a match",
Value: [2, 3, 4]
},
{
note: "I'm not a match either",
Value: [78, 4, 27]
},
{
note: "I'm a match",
Value: [889, 5, 27]
},
{
note: "I'm also a match, but you won't find me",
Value: [4, 6, 5]
}
];
var gettedcustomObject = customList.find(function(entry) {
return entry.Value.indexOf(5) != -1;
});
console.log(gettedcustomObject);
If your logic matching the item inside Value were more complicated, you'd use Array#some and a callback function rathe than indexOf. But when looking to see if an array for an entry in an array based on ===, indexOf or the new Array#includes are the way to go.
one approach using Array.some() and Array.indexOf(). some loop break once the element is found
var gettedcustomObject;
customobject.some(function(obj){
if(obj.value.indexOf(5) >-1){
gettedcustomObject = obj;
return true;
}
});

Javascript array find alternative

I'm looking for an alternative for the find() method of an array. I'm using it on Android Browser and Array.prototype.find() doesn't work there. Definition Array Support
var test= this.arrayOfValues.find(function (value) {
return (value.name === device.value)
});
If you do not care so much about programming your own, and if indexOf is somehow not usable, have a look at Underscore.js#find. As an alternative, as #NinaScholz recommended in the comments, use the Polyfill from mozilla.org:
if (!Array.prototype.find) {
Array.prototype.find = function(predicate) {
if (this === null) {
throw new TypeError('Array.prototype.find called on null or undefined');
}
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
}
var list = Object(this);
var length = list.length >>> 0;
var thisArg = arguments[1];
var value;
for (var i = 0; i < length; i++) {
value = list[i];
if (predicate.call(thisArg, value, i, list)) {
return value;
}
}
return undefined;
};
}

How is `each` different from `for-loop` when returning a value?

I have my each function which I created to emulate Underscore.js's _each() for my Javascript study.
var each = function(list, iteratee) {
if (Array.isArray(list)) { // list is array
for (var i = 0; i < list.length; i++) {
iteratee(list[i], i, list);
}
} else if (list.constructor === Object) { // list is object
for (var key in list) {
iteratee(list[key], key, list);
}
}
};
Then I wanted to create a function find which is also available from Underscore.js. This function looks through each value in the list, returning the first one that passes a truth test (predicate), or
undefined if no value passes the test. The function returns as soon as it finds an acceptable element and doesn't traverse the entire list.
Here is my version of find that I came up with.
var find = function(list, predicate) {
each(list, function(elem){
if (predicate(elem)) {
return elem;
}
});
};
I thought it would return a value immediately after it has found a true value for an element that passes a test from an external predicate function. But instead, it's giving me an undefined.
Below code works as I expected. But why would they provide different output?
var find = function(list, predicate) {
if (Array.isArray(list)) { // list is array
for (var i = 0; i < list.length; i++) {
if (predicate(list[i])) {
return list[i];
}
}
} else if (list.constructor === Object) { // list is object
for (var key in list) {
if (predicate(list[key])) {
return list[key];
}
}
}
};
What I don't understand is that why doesn't each works as I expected when I included it in my find function. Wouldn't they simply different in terms of their style of expression? In other word, one is functional style, and another is not?
This is caused due to the lack of return statement.
Each function iterates over find but doesn't return anything. return statement in predicate returns the output to the each function where it is not expected
Example of working function:
var find = function(list, predicate) {
var res = undefined/null/whatever;
each(list, function(elem) {
if (predicate(elem)) {
res = elem;
}
});
return res;
};
However this function is not efficient as it won't stop when result is found
This has to do with how return works. Let's look at your code:
var find = function(list, predicate) {
// you pass list and an anonymous callback to `each`
each(list, function (elem) {
// if this condition is true
if (predicate(elem)) {
// return elem
return elem;
}
});
}
The problem is that return elem applies to the anonymous callback, not the find function.
If you want to be able to "break" the each loop, you can check the current state on each iteration of the for-loop within each.
// only going to write for arrays
var each = function (list, iteratee) {
for (var i = 0; i < list.length; i++) {
if (iteratee(list[i], i, list)) continue;
else break;
}
});
// then in find:
var find = function (list, predicate) {
var ret = null
each(list, function(elem) {
if (predicate(elem)) {
ret = elem;
return false; // return false, since we no longer wish to continue
}
});
return ret;
};
A second solution is to return from within the each loop:
var each = function (list, iteratee) {
for (var i = 0; i < list.length; i++) {
if (iteratee(list[i], i, list)) {
continue;
} else {
return list[i];
}
}
// didn't find anything, so `return null`
return null;
});
var find = function (list, predicate) {
return each(list, function(elem) {
// if `predicate`, return false, so the loop breaks
return !predicate(elem);
});
};
The only problem I have with this solution is that it distorts the meaning of each. each intuitively means "go through everything," which the second solution doesn't necessarily do.

how to get length of javascript "array"

We have been using javascript "hashes" a lot lately, and we've been looking for a universal way to count the items contained in both arrays and hashes without having to "know" which we're dealing with except in the count method. As everyone knows .length is useless since it only returns the value of the highest index in the array. What we have below does not work because hashes test true for Array, but the length value returned is crap for hashes. We originally replaced .length all over our project with Object.keys().length, but this isn't supported in IE8 and lower.
This is such a stupid simple thing and we can't seem to get it working. Help me, Obi Wan. You're my only hope!
function isNullOrUndefined(aObject) {
"use strict";
return (typeof aObject === 'undefined' || aObject === null);
}
function count(aList) {
"use strict";
var lKey = null,
lResult = 0;
if (!isNullOrUndefined(aList)) {
if (aList.constructor == Array) {
lResult = aList.length;
} else if (!isNullOrUndefined(Object.keys)) {
lResult = Object.keys(aList).length;
} else {
for (lKey in aList) {
if (aList.hasOwnProperty(lKey)) {
lResult++;
}
}
}
}
return lResult;
}
Object.keys polyfill copied verbatim from the ES5-shim
// ES5 15.2.3.14
// http://es5.github.com/#x15.2.3.14
if (!Object.keys) {
// http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
var hasDontEnumBug = true,
dontEnums = [
"toString",
"toLocaleString",
"valueOf",
"hasOwnProperty",
"isPrototypeOf",
"propertyIsEnumerable",
"constructor"
],
dontEnumsLength = dontEnums.length;
for (var key in {"toString": null}) {
hasDontEnumBug = false;
}
Object.keys = function keys(object) {
if ((typeof object != "object" && typeof object != "function") || object === null) {
throw new TypeError("Object.keys called on a non-object");
}
var keys = [];
for (var name in object) {
if (owns(object, name)) {
keys.push(name);
}
}
if (hasDontEnumBug) {
for (var i = 0, ii = dontEnumsLength; i < ii; i++) {
var dontEnum = dontEnums[i];
if (owns(object, dontEnum)) {
keys.push(dontEnum);
}
}
}
return keys;
};
}
Despise the answer from Raynos that is completely valid please consider performance
This is how my hash object look like
function Hash(){
this.values = [];
this.keys = {};
}
Hash.prototype.set = function(key, val){
if(this.keys[key]){
this.values[this.keys[key]] = value
}else{
this.keys[key] = (this.values.push(val)-1)
}
}
Hash.prototype.length = function(){
return this.values.length
}
Why I do this is simple performance looping through an object to count the properties length will be really inefficient the solution above give you direct access all the time.

Categories

Resources