Is there any good JavaScript hash(code/table) implementation out there? - javascript

Yes, I know you could use regular objects as associative arrays in JavaScript, but I'd like to use something closer to java's Map's implementation (HashMap, LinkedHashMap etc). Something that could have any kind of data used as key. Are there any good hash(code/table) in JavaScript implementation out there?

In javascript, objects are literally a hash implementation. A Java HashMap will be a little bit of a fake-out, so I'd challenge you to re-think your needs.
The straight answer is no, I don't believe that there is a great implementation of Java's HashMap in javascript. If there is, it's bound to be part of a library that you may or may not want to use, and you certainly don't need to include a library just to have a little hash table.
So let's go ahead and write one, just to examine the problem. You can use it if you like. We'll just start by writing a constructor, and we'll piggyback off of Array, which is Object, but has some useful methods that will keep this example from getting too tedious:
function HashMap () {
var obj = [];
return obj;
}
var myHashMap = HashMap();
We'll add some methods straight from the world of Java, but translate into javascript as we go...
function HashMap() {
var obj = [];
obj.size = function () {
return this.length;
};
obj.isEmpty = function () {
return this.length === 0;
};
obj.containsKey = function (key) {
for (var i = 0; i < this.length; i++) {
if (this[i].key === key) {
return i;
}
}
return -1;
};
obj.get = function (key) {
var index = this.containsKey(key);
if (index > -1) {
return this[index].value;
}
};
obj.put = function (key, value) {
if (this.containsKey(key) !== -1) {
return this.get(key);
}
this.push({'key': key, 'value': value});
};
obj.clear = function () {
this = null; // Just kidding...
};
return obj;
}
We could continue to build it out, but I think it's the wrong approach. At the end of the day, we end up using what javascript provides behind the scenes, because we just simply don't have the HashMap type. In the process of pretending, it lends itself to all kinds of extra work.
It's a bit ironic that one of the things that makes javascript such an interesting and diverse language is the ease with which it handles this kind of wrestling. We can literally do anything we'd like, and the quick example here does nothing if it doesn't illustrate the deceptive power of the language. Yet given that power, it seems best not to use it.
I just think javascript wants to be lighter. My personal recommendation is that you re-examine the problem before you try implement a proper Java HashMap. Javascript neither wants nor affords for one.
Remember the native alternative:
var map = [{}, 'string', 4, {}];
..so fast and easy by comparison.
On the other hand, I don't believe that there are any hard-and-fast answers here. This implementation really may be a perfectly acceptable solution. If you feel you can use it, I'd say give it a whirl. But I'd never use it if I felt that we have reasonably simpler and more natural means at our disposal.. which I'm almost certain that we do.
Sidenote:
Is efficiency related to style? Notice the performance hit.. there's a big O staring us in the face at HashMap.put()... The less-than-optimal performance probably isn't a show-stopper here, and you'd probably need to be doing something very ambitious or have a large set of data before you'd even notice a performance hickup a modern browser. It's just interesting to note that operations tend to become less efficient when you're working against the grain, almost as if there is a natural entropy at work. Javascript is a high level language, and should offer efficient solutions when we keep in line with its conventions, just as a HashMap in Java will be a much more natural and high performing choice.

I have released a standalone JavaScript hash table implementation that goes further than those listed here.
http://www.timdown.co.uk/jshashtable/

Note that java collections using "any kind of object" as a key isn't quite right. Yes, you can use any object, but unless that object has good hashcode() and equals() implementations then it won't work well. The base Object class has a default implementation for these, but for custom classes to work (effectively) as hashtable keys you need to override them. Javascript has no equivalent (that I know of).
To create a hashtable in javascript that can (effectively) use arbitrary objects as the key you'd need to enforce something similar on the objects you use, at least if you want to keep the performance gains of a hashtable. If you can enforce a 'hashcode()' method that returns a String, then you can just use an Object under the hood as the actual hashtable.
Otherwise, you'd need to so something like the other solutions posted, which as of right now do not perform like hashtables. They both do O(n) searches over the list to try and find the key, which pretty much defeats the purpose of a hashtable (hashtables are generally constant time for get/put).

Here's a naive implementation I just put together - as keparo mentioned in a comment, one of the big issues is equality checking:
var ObjectMap = function()
{
this._keys = [];
this._values = [];
};
ObjectMap.prototype.clear = function()
{
this._keys = [];
this._values = [];
};
ObjectMap.prototype.get = function(key)
{
var index = this._indexOf(key, this._keys);
if (index != -1)
{
return this._values[index];
}
return undefined;
};
ObjectMap.prototype.hasKey = function(key)
{
return (this._indexOf(key, this._keys) != -1);
};
ObjectMap.prototype.hasValue = function(value)
{
return (this._indexOf(value, this._values) != -1);
};
ObjectMap.prototype.put = function(key, value)
{
var index = this._indexOf(key, this._keys);
if (index == -1)
{
index = this._keys.length;
}
this._keys[index] = key;
this._values[index] = value;
};
ObjectMap.prototype.remove = function(key)
{
var index = this._indexOf(key, this._keys);
if (index != -1)
{
this._keys.splice(index, 1);
this._values.splice(index, 1);
}
};
ObjectMap.prototype.size = function()
{
return this._keys.length;
};
ObjectMap.prototype._indexOf = function(item, list)
{
for (var i = 0, l = list.length; i < l; i++)
{
if (this._equals(list[i], item))
{
return i;
}
}
return -1;
};
ObjectMap.prototype._equals = function(a, b)
{
if (a === b)
{
return true;
}
// Custom objects can implement an equals method
if (typeof a.equals == "function" &&
typeof b.equals == "function")
{
return a.equals(b);
}
// Arrays are equal if they're the same length and their contents are equal
if (a instanceof Array && b instanceof Array)
{
if (a.length != b.length)
{
return false;
}
for (var i = 0, l = a.length; i < l; i++)
{
if (!this._equals(a[i], b[i]))
{
return false;
}
}
return true;
}
// Checking object properties - objects are equal if they have all the same
// properties and they're all equal.
var seenProperties = {};
for (var prop in a)
{
if (a.hasOwnProperty(prop))
{
if (!b.hasOwnProperty(prop))
{
return false;
}
if (!this._equals(a[prop], b[prop]))
{
return false;
}
seenProperties[prop] = true;
}
}
for (var prop in b)
{
if (!(prop in seenProperties) && b.hasOwnProperty(prop))
{
if (!a.hasOwnProperty(prop))
{
return false;
}
if (!this._equals(b[prop], a[prop]))
{
return false;
}
}
}
return true;
};
Example usage:
>>> var map = new ObjectMap();
>>> var o = {a: 1, b: [1,2], c: true};
>>> map.put(o, "buns");
>>> map.get(o)
"buns"
>>> map.get({a: 1, b: [1,2], c: true});
"buns"
>>> map.get({a: 1, b: [1,2], c: true, d:"hi"});
>>> var a = [1,2,3];
>>> map.put(a, "cheese");
>>> map.get(a);
"cheese"
>>> map.get([1,2,3]);
"cheese"
>>> map.get([1,2,3,4]);
>>> var d = new Date();
>>> map.put(d, "toast");
>>> map.get(d);
"toast"
>>> map.get(new Date(d.valueOf()));
"toast"
This is in no way a complete implementation, just a pointer for a way to implement such an object. For example, looking at what I've given, you would also need to add constructor property checks before the object property check, as this currently works:
>>> function TestObject(a) { this.a = a; };
>>> var t = new TestObject("sandwich");
>>> map.put(t, "butter");
>>> map.get({a: "sandwich"})
"butter"

Related

Allocation-free abstractions in Javascript

I have a general question which is about whether it is possible to make zero-allocation iterators in Javascript. Note that by "iterator" I am not married to the current definition of iterator in ECMAScript, but just a general pattern for iterating over user-defined ranges.
To make the problem concrete, say I have a list like [5, 5, 5, 2, 2, 1, 1, 1, 1] and I want to group adjacent repetitions together, and process it into a form which is more like [5, 3], [2, 2], [1, 4]. I then want to access each of these pairs inside a loop, something like "for each pair in grouped(array), do something with pair". Furthermore, I want to reuse this grouping algorithm in many places, and crucially, in some really hot inner loops (think millions of loops per second).
Question: Is there an iteration pattern to accomplish this which has zero overhead, as if I hand-wrote the loop myself?
Here are the things I've tried so far. Let's suppose for concreteness that I am trying to compute the sum of all pairs. (To be clear I am not looking for alternative ways of writing this code, I am looking for an abstraction pattern: the code is just here to provide a concrete example.)
Inlining the grouping code by hand. This method performs the best, but obscures the intent of the computation. Furthermore, inlining by hand is error-prone and annoying.
function sumPairs(array) {
let sum = 0
for (let i = 0; i != array.length; ) {
let elem = array[i++], count = 1
while (i < array.length && array[i] == elem) { i++; count++; }
// Here we can actually use the pair (elem, count)
sum += elem + count
}
return sum
}
Using a visitor pattern. We can write a reduceGroups function which will call a given visitor(acc, elem, count) for each pair (elem, count), similar to the usual Array.reduce method. With that our computation becomes somewhat clearer to read.
function sumPairsVisitor(array) {
return reduceGroups(array, (sofar, elem, count) => sofar + elem + count, 0)
}
Unfortunately, Firefox in particular still allocates when running this function, unless the closure definition is manually moved outside the function. Furthermore, we lose the ability to use control structures like break unless we complicate the interface a lot.
Writing a custom iterator. We can make a custom "iterator" (not an ES6 iterator) which exposes elem and count properties, an empty property indicating that there are no more pairs remaining, and a next() method which updates elem and count to the next pair. The consuming code looks like this:
function sumPairsIterator(array) {
let sum = 0
for (let iter = new GroupIter(array); !iter.empty; iter.next())
sum += iter.elem + iter.count
return sum
}
I find this code the easiest to read, and it seems to me that it should be the fastest method of abstraction. (In the best possible case, scalar replacement could completely collapse the iterator definition into the function. In the second best case, it should be clear that the iterator does not escape the for loop, so it can be stack-allocated). Unfortunately, both Chrome and Firefox seem to allocate here.
Of the approaches above, the custom-defined iterator performs quite well in most cases, except when you really need to put the pedal to the metal in a hot inner loop, at which point the GC pressure becomes apparent.
I would also be ok with a Javascript post-processor (the Google Closure Compiler perhaps?) which is able to accomplish this.
Check this out. I've not tested its performance but it should be good.
(+) (mostly) compatible to ES6 iterators.
(-) sacrificed ...GroupingIterator.from(arr) in order to not create a (imo. garbage) value-object. That's the mostly in the point above.
afaik, the primary use case for this is a for..of loop anyways.
(+) no objects created (GC)
(+) object pooling for the iterators; (again GC)
(+) compatible with controll-structures like break
class GroupingIterator {
/* object pooling */
static from(array) {
const instance = GroupingIterator._pool || new GroupingIterator();
GroupingIterator._pool = instance._pool;
instance._pool = null;
instance.array = array;
instance.done = false;
return instance;
}
static _pool = null;
_pool = null;
/* state and value / payload */
array = null;
element = null;
index = 0;
count = 0;
/* IteratorResult interface */
value = this;
done = true;
/* Iterator interface */
next() {
const array = this.array;
let index = this.index += this.count;
if (!array || index >= array.length) {
return this.return();
}
const element = this.element = array[index];
while (++index < array.length) {
if (array[index] !== element) break;
}
this.count = index - this.index;
return this;
}
return() {
this.done = true;
// cleanup
this.element = this.array = null;
this.count = this.index = 0;
// return iterator to pool
this._pool = GroupingIterator._pool;
return GroupingIterator._pool = this;
}
/* Iterable interface */
[Symbol.iterator]() {
return this;
}
}
var arr = [5, 5, 5, 2, 2, 1, 1, 1, 1];
for (const item of GroupingIterator.from(arr)) {
console.log("element", item.element, "index", item.index, "count", item.count);
}

Is an array.forEach with a splice the best way to remove an entry from an array of unique Ids?

I have an array of objects. Each object has a unique userTestrId. Here is the code that I am using when I want to delete one of the objects. Is this the most efficient way I can perform the delete? What I am concerned with is once a row has been deleted the code will still go all the way through the array even though there is no chance of another entry:
var id = 99;
self.tests.forEach(function (elem, index) {
if (elem['userTestId'] === id)
self.tests.splice(index, 1);
});
}
var id = 99;
self.tests.some(function (elem, index) {
if (elem['userTestId'] === id)
self.tests.splice(index, 1);
return true;
});
return false;
}
Could utilise Array.some? Stops looping once you return TRUE from a callback.
This is an alternative to #benhowdle89's answer.
Use Array.prototype.every
The .every method is used to iterate over an array and check whether each and every element passes a test or not. If the callback returns false for any single element, the loop breaks.
Take the following example:
var odds = [3, 5, 7, 9, 11, 12, 17, 19];
//an array with all odd numbers except one
var checkEven = function (n, i, arr) {
console.log ("Checking number ", n);
if (n%2===0) {
arr.splice(i, 1);
return false;
}
return true;
}
console.log(odds.every(checkEven), odds);
If you run the above and look at the console, the loop executed till number 12 only, where it spliced, and stopped.
You can employ similar logic in your code very easily :)
var id = 99;
self.tests.some(function (elem, index) {
if (elem['userTestId'] === id)
self.tests.splice(index, 1);
return true;
});
return false;
}
Polyfill :
some was added to the ECMA-262 standard in the 5th edition; as such it may not be present in all implementations of the standard. You can work around this by inserting the following code at the beginning of your scripts, allowing use of some in implementations which do not natively support it.
// 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;
};
}
see in detail
While your concern is technically correct, it's unlikely to be an actual problem(Javascript is fast, this is a microoptimization).
What you should do is focus on using the appropriate interface, so your code could be easy to read and understand. .forEach() does not tell you what you want to do, unless you really do want to do something with each element of the array.
Lodash has the .remove() function, which removes all elements matching a predicate. Unfortunately, I couldn't find the exact specific function you wanted in JS's standard library or in lodash, so you would have to write your own wrapper:
var id = 99
removeFirst(tests, function (elem) { return elem.userTestId === id })
function removeFirst(array, callback) {
var index = array.findIndex(callback)
array.splice(index, 1)
}
Having noted that, you should avoid using an array at all - splicing is way more expensive than looping the whole array to begin with! Instead, since you have a unique identifier, you could use a map:
var map = {}
tests.forEach(function mapper(elem) {
map[elem.userTestId] = elem
})
Now, your removal function is simply delete map[id].

Check if array[4][3][7][3] is defined

When there is a single dimension array, it is easy to check whether it is defined, by either simple calling arr[6] which will return undefined if such property does not exist or calling typeof arr[6] === undefined.
The problem is, that in my case I have arr[5][1][6][2][5][3][7], where arr[5] can be non existent, or arr[5][1], etc. Which will naturally trigger error: TypeError: Cannot read property [..] One solution is to write many IF statements. However, is there any better solution, that'd simple allow me to check whether arr[5][1][6][2][5][3][7] is defined?
I can't think of anything better than:
var defined = false;
try {
defined = !!arr[5][1][6][2][5][3][7]
} catch(e)
{
// nothing
}
But seriously bad design.
Since this seemed like an interesting problem, I wrote this function to solve it in a nice an non-exceptional way :)
var deepCheck = function(arr, indexes) {
var level = arr;
while(indexes.length) {
var v = indexes.shift()
if(!level[v]) {
return false;
}
level = level[v];
}
return true;
};
Now say you have this:
arr[foo][bar][baz];
You would check it using...
deepCheck(arr, [foo, bar, baz]);
Maybe I should point out that I do kind of agree that if you indeed have very very long arrays like that, it does sound like a design issue.
By using a try/catch block you can check if the element can be accessed.
var x;
try {
x = arr[5][1][6][2][5][3][7];
} catch(TypeError)
{
// the element cannot be accessed
x = undefined;
}
Then it's easy enough to check if 'x' is defined or not using an if statement.
A pragmatic approach would be to break this problem down into its component parts; look at what data is known and the tools you have at hand.
So, what do we know - well we know the keys that we want to inspect, in the case of checking if arr[5][1][6][2][5][3][7] is defined. Now ask yourself, what tools do we have in JavaScript? To check if an Array index is defined we can compare against null, ie:
if (array[index] === null) {
return false
}
If we were to try and write this code, one of the first things that should come to mind is to simply walk through each key, in order: eg:
if (array[5] === null) {
return false;
} else if (array[5][1] === null) {
return false
} ...snip...
// Good news, it's defined!
return true
Obviously this approach can be improved, it requires a tonne of duplicated code to be written out, it's inflexible and not reusable. If you ever find yourself doing the same thing over and over, you probably have a good candidate for a loop construct. In order for a loop you need a variant, something that will change with each repetition - in the example above the variant is the right most element of the nested array we are inspecting. First, let's start by listing our variants out:
var variants = [ 5, 1, 6, 2, 5, 3, 7 ];
for (var i = 0; i < variants.length; i++) {
console.log("variant: " + variants[i]);
}
Where, do we go from here? Well things get a bit harder, you need to understand how Arrays are passed by reference in JavaScript and exploit that in the loop body; ultimately you may end up with something like this:
function arrayDimensionsExist(source, dimensions) {
var currentDepth = source;
for (var i = 0; i < dimensions.length; i++) {
var key = dimensions[i];
if (currentDepth[key] === null) {
return false;
} else {
currentDepth = source[key];
}
}
return true;
}
Put the code accessing it between try and catch. If it works, it works, if not you get a nice exception and you can react accordingly.
As a side note, I shudder to think of what prompted you to design your system like that...
There's no solution built-in to the language, but you could handle it with a function like this:
var verifyIndexes = function(target) {
var current = target;
for (i = 1; i < arguments.length; i++) {
if (arguments[i] in current) {
current = current[arguments[i]];
} else {
return false;
}
}
return true;
}
var myArray = [[[1, 2, 3], 4], 5];
console.log(verifyIndexes(myArray, 0)); // true
console.log(verifyIndexes(myArray, 0, 0, 0)); // true
console.log(verifyIndexes(myArray, 0, 0, 3)); // false
console.log(verifyIndexes(myArray, 0, 1)); // true
console.log(verifyIndexes(myArray, 0, 2)); // false

How to determine if object is in array [duplicate]

This question already has answers here:
How do I check if an array includes a value in JavaScript?
(60 answers)
Closed 29 days ago.
I need to determine if an object already exists in an array in javascript.
eg (dummycode):
var carBrands = [];
var car1 = {name:'ford'};
var car2 = {name:'lexus'};
var car3 = {name:'maserati'};
var car4 = {name:'ford'};
carBrands.push(car1);
carBrands.push(car2);
carBrands.push(car3);
carBrands.push(car4);
now the "carBrands" array contains all instances.
I'm now looking a fast solution to check if an instance of car1, car2, car3 or car4 is already in the carBrands array.
eg:
var contains = carBrands.Contains(car1); //<--- returns bool.
car1 and car4 contain the same data but are different instances they should be tested as not equal.
Do I have add something like a hash to the objects on creation? Or is there a faster way to do this in Javascript.
I am looking for the fastest solution here, if dirty, so it has to be ;) In my app it has to deal with around 10000 instances.
no jquery
Use something like this:
function containsObject(obj, list) {
var i;
for (i = 0; i < list.length; i++) {
if (list[i] === obj) {
return true;
}
}
return false;
}
In this case, containsObject(car4, carBrands) is true. Remove the carBrands.push(car4); call and it will return false instead. If you later expand to using objects to store these other car objects instead of using arrays, you could use something like this instead:
function containsObject(obj, list) {
var x;
for (x in list) {
if (list.hasOwnProperty(x) && list[x] === obj) {
return true;
}
}
return false;
}
This approach will work for arrays too, but when used on arrays it will be a tad slower than the first option.
Why don't you use the indexOf method of javascript arrays?
Check this out: MDN indexOf Arrays
Simply do:
carBrands.indexOf(car1);
It will return you the index (position in the array) of car1. It will return -1 if car1 was not found in the array.
http://jsfiddle.net/Fraximus/r154cd9o
Edit: Note that in the question, the requirements are to check for the same object referenced in the array, and NOT a new object. Even if the new object is identical in content to the object in the array, it is still a different object.
As mentioned in the comments, objects are passed by reference in JS and the same object can exist multiple times in multiple structures.
If you want to create a new object and check if the array contains objects identical to your new one, this answer won't work (Julien's fiddle below), if you want to check for that same object's existence in the array, then this answer will work. Check out the fiddles here and in the comments.
Having been recently bitten by the FP bug reading many wonderful accounts of how neatly the functional paradigm fits with Javascript
I replicate the code for completeness sake and suggest two ways this can be done functionally.
var carBrands = [];
var car1 = {name:'ford'};
var car2 = {name:'lexus'};
var car3 = {name:'maserati'};
var car4 = {name:'ford'};
var car5 = {name:'toyota'};
carBrands.push(car1);
carBrands.push(car2);
carBrands.push(car3);
carBrands.push(car4);
// ES6 approach which uses the includes method (Chrome47+, Firefox43+)
carBrands.includes(car1) // -> true
carBrands.includes(car5) // -> false
If you need to support older browsers use the polyfill, it seems IE9+ and Edge do NOT support it. Located in polyfill section of MSDN page
Alternatively I would like to propose an updated answer to cdhowie
// ES2015 syntax
function containsObject(obj, list) {
return list.some(function(elem) {
return elem === obj
})
}
// or ES6+ syntax with cool fat arrows
function containsObject(obj, list) {
return list.some(elem => elem === obj)
}
try Array.prototype.some()
MDN Array.prototype.some
function isBiggerThan10(element, index, array) {
return element > 10;
}
[2, 5, 8, 1, 4].some(isBiggerThan10); // false
[12, 5, 8, 1, 4].some(isBiggerThan10); // true
You could use jQuery's grep method:
$.grep(carBrands, function(obj) { return obj.name == "ford"; });
But as you specify no jQuery, you could just make a derivative of the function. From the source code:
function grepArray( elems, callback, inv ) {
var ret = [];
// Go through the array, only saving the items
// that pass the validator function
for ( var i = 0, length = elems.length; i < length; i++ ) {
if ( !inv !== !callback( elems[ i ], i ) ) {
ret.push( elems[ i ] );
}
}
return ret;
}
grepArray(carBrands, function(obj) { return obj.name == "ford"; });
I used underscore javascript library to tweak this issue.
function containsObject(obj, list) {
var res = _.find(list, function(val){ return _.isEqual(obj, val)});
return (_.isObject(res))? true:false;
}
please refer to underscore.js documentation for the underscore functions used in the above example.
note: This is not a pure javascript solution. Shared for educational purposes.
You can just use the equality operator: ==. Objects are checked by reference by default, so you don't even need to use the === operator.
try this, just make sure you're using the correct variable reference in the place of car1:
var i, car, l = cars.length;
for (i = 0; i < l; i++)
{
if ((car = cars[i]) == car1)
{
break;
}
else car = null;
}
Edit to add:
An array extension was mentioned, so here's the code for it:
Array.prototype.contains = Array.prototype.contains || function(obj)
{
var i, l = this.length;
for (i = 0; i < l; i++)
{
if (this[i] == obj) return true;
}
return false;
};
Note that I'm caching the length value, as the Array's length property is actually an accessor, which is marginally slower than an internal variable.
I would use a generic iterator of property/value over the array. No jQuery required.
arr = [{prop1: 'val1', prop2: 'val2'}, {prop1: 'val3', prop2: 'val4'}];
objectPropInArray(arr, 'prop1', 'val3'); // <-- returns true
function objectPropInArray(list, prop, val) {
if (list.length > 0 ) {
for (i in list) {
if (list[i][prop] === val) {
return true;
}
}
}
return false;
}
You could try sorting the array based on a property, like so:
carBrands = carBrands.sort(function(x,y){
return (x == y) ? 0 : (x > y) ? 1 : -1;
});
Then you can use an iterative routine to check whether
carBrands[Math.floor(carBrands.length/2)]
// change carBrands.length to a var that keeps
// getting divided by 2 until result is the target
// or no valid target exists
is greater or lesser than the target, and so on, which will let you go through the array quickly to find whether the object exists or not.
try this ,
You can use the JavaScript some() method to find out if a JavaScript array contains an object.
<script>
// An array of objects
var persons = [{name: "Harry"}, {name: "Alice"}, {name: "Peter"}];
// Find if the array contains an object by comparing the property value
if(persons.some(person => person.name === "Peter")){
alert("Object found inside the array.");
} else{
alert("Object not found.");
}
</script>
EDIT 05/18/2022
The most simple way using ES6:
const arrayContainsObject = <T extends Record<string, unknown>>(array: T[], object: T) => {
return array.some(item => Object.keys(item).every(key => item[key] === object[key]))
}
Use like so:
const arr = [{
prop1: 'value1',
prop2: 'value2'
}]
const obj1 = {
prop1: 'value1',
prop2: 'value2'
}
const obj2 = {
prop2: 'value2',
prop1: 'value1'
}
const obj3 = {
prop0: 'value0',
prop1: 'value1'
}
arrayContainsObject(arr, obj1) // true
arrayContainsObject(arr, obj2) // true, even when props are arranged in different order
arrayContainsObject(arr, obj3) // false
Previous answer, don't use (because the order of props in an object needs to be identical)
const arr = [{
prop: 'value'
}]
const obj = {
prop: 'value'
}
arr.some((e) => Object.entries(e).toString() === Object.entries(obj).toString()) // true
i know this is an old post, but i wanted to provide a JQuery plugin version and my code.
// Find the first occurrence of object in list, Similar to $.grep, but stops searching
function findFirst(a,b){
var i; for (i = 0; i < a.length; ++i) { if (b(a[i], i)) return a[i]; } return undefined;
}
usage:
var product = $.findFirst(arrProducts, function(p) { return p.id == 10 });
This function is to check for a unique field.
Arg 1: the array with selected data
Arg 2: key to check
Arg 3: value that must be "validated"
function objectUnique( array, field, value )
{
var unique = true;
array.forEach(function ( entry )
{
if ( entry[field] == value )
{
unique = false;
}
});
return unique;
}
you can use Array.find().
in your case is going to look like this
carBrands.find(function(car){
let result = car.name === 'ford'
if (result == null){
return false;
} else {
return true
}
});
if car is not null it will return the javaScript Object which contains the string 'ford'
The issue with many of the answers here is that they will NOT find an object in an array that is equal to another object. They will only search for an EXISTING object that has a pointer to it in an array.
Quick fix using lodash to see if ANY equal object is in an array:
import _ from 'lodash';
_.find(carBrands, car1); //returns object if true, undefined if false
Working Plunker using this method: https://plnkr.co/edit/y2YX9o7zkQa2r7lJ
if its possible to use es6
carBrands.filter(carBrand => carBrand.name === carX.name).length > 0
if it's true there is a similarity
You can convert both the JSON objects to string and simply check if the bigger json contains the smaller json.
console.log(JSON.stringify(carBrands).includes(JSON.stringify(car1))); // true
console.log(JSON.stringify(carBrands).includes(JSON.stringify(car5))); // false
You could also a the findIndex
var carBrands = [];
var car1 = {name:'ford'};
var car2 = {name:'lexus'};
carBrands.push(car1);
if (carBrands.findIndex(f => f.name === car1.name) === -1) {
console.log('not contain')
} else {
console.log('contain')
}
if (carBrands.findIndex(f => f.name === car2.name) === -1) {
console.log('not contain')
} else {
console.log('contain')
}

Three map implementations in javascript. Which one is better?

I wrote a simple map implementation for some task. Then, out of curiosity, I wrote two more. I like map1 but the code is kinda hard to read. If somebody is interested, I'd appreciate a simple code review.
Which one is better? Do you know some other way to implement this in javascript?
var map = function(arr, func) {
var newarr = [];
for (var i = 0; i < arr.length; i++) {
newarr[i] = func(arr[i]);
}
return newarr;
};
var map1 = function(arr, func) {
if (arr.length === 0) return [];
return [func(arr[0])].concat(funcmap(arr.slice(1), func));
};
var map2 = function(arr, func) {
var iter = function(result, i) {
if (i === arr.length) return result;
result.push(func(arr[i]));
return iter(result, i+1);
};
return iter([], 0);
};
Thanks!
EDIT
I am thinking about such function in general.
For example, right now I am going to use it to iterate like this:
map(['class1', 'class2', 'class3'], function(cls) {
el.removeClass(cls);
});
or
ids = map(elements, extract_id);
/* elements is a collection of html elements,
extract_id is a func that extracts id from innerHTML */
What about the map implementation used natively on Firefox and SpiderMonkey, I think it's very straight forward:
if (!Array.prototype.map) {
Array.prototype.map = function(fun /*, thisp*/) {
var len = this.length >>> 0; // make sure length is a positive number
if (typeof fun != "function") // make sure the first argument is a function
throw new TypeError();
var res = new Array(len); // initialize the resulting array
var thisp = arguments[1]; // an optional 'context' argument
for (var i = 0; i < len; i++) {
if (i in this)
res[i] = fun.call(thisp, this[i], i, this); // fill the resulting array
}
return res;
};
}
If you don't want to extend the Array.prototype, declare it as a normal function expression.
As a reference, map is implemented as following in jQuery
map: function( elems, callback ) {
var ret = [];
// Go through the array, translating each of the items to their
// new value (or values).
for ( var i = 0, length = elems.length; i < length; i++ ) {
var value = callback( elems[ i ], i );
if ( value != null )
ret[ ret.length ] = value;
}
return ret.concat.apply( [], ret );
}
which seems most similar to your first implementation. I'd say the first one is preferred as it is the simplest to read and understand. But if performance is your concern, profile them.
I think that depends on what you want map to do when func might change the array. I would tend to err on the side of simplicity and sample length once.
You can always specify the output size as in
var map = function(arr, func) {
var n = arr.length & 0x7fffffff; // Make sure n is a non-neg integer
var newarr = new Array(n); // Preallocate array size
var USELESS = {};
for (var i = 0; i < n; ++i) {
newarr[i] = func.call(USELESS, arr[i]);
}
return newarr;
};
I used the func.call() form instead of just func(...) instead since I dislike calling user supplied code without specifying what 'this' is, but YMMV.
This first one is most appropriate. Recursing one level for every array item may make sense in a functional language, but in a procedural language without tail-call optimisation it's insane.
However, there is already a map function on Array: it is defined by ECMA-262 Fifth Edition and, as a built-in function, is going to be the optimal choice. Use that:
alert([1,2,3].map(function(n) { return n+3; })); // 4,5,6
The only problem is that Fifth Edition isn't supported by all current browsers: in particular, the Array extensions are not present in IE. But you can fix that with a little remedial work on the Array prototype:
if (!Array.prototype.map) {
Array.prototype.map= function(fn, that) {
var result= new Array(this.length);
for (var i= 0; i<this.length; i++)
if (i in this)
result[i]= fn.call(that, this[i], i, this);
return result;
};
}
This version, as per the ECMA standard, allows an optional object to be passed in to bind to this in the function call, and skips over any missing values (it's legal in JavaScript to have a list of length 3 where there is no second item).
There's something wrong in second method. 'funcmap' shouldn't be changed to 'map1'?
If so - this method loses, as concat() method is expensive - creates new array from given ones, so has to allocate extra memory and execute in O(array1.length + array2.length).
I like your first implementation best - it's definitely easiest to understand and seems quick in execution to me. No extra declaration (like in third way), extra function calls - just one for loop and array.length assignments.
I'd say the first one wins on simplicity (and immediate understandability); performance will be highly dependent on what the engine at hand optimizes, so you'd have to profile in the engines you want to support.

Categories

Resources