This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Easiest way to find duplicate values in a JavaScript array
I am looking to find if two values are the same in an Array. I have written the following code:
function validatePassTimeFields(passtimes) {
var success = true;
var length = passtimes.length;
var hashMap = new Object();
for (var j=0; j<length; j++) {
if(hashMap[passtimes[j].value]==1) {
success = false;
alert("Duplicate Found");
break;
}
hashMap[passtimes[j].value]=1;
}
return success;
}
I am new to Javascript, so I tried using HashMap like to find if there is any duplicate. IS it the best way of finding a duplicate in JavaScript? or I can optimize it?
Your function is already very good, apart from the issue that it only works for arrays with strings or numbers. For a more difficile approach to care also about objects see this answer. I don't think that matters for you as you have an explicit and restricted use case (checking identity by the value property).
However, some points I'd do different:
Don't use the success variable and break from the loop, but just return from the whole function.
Instead of the constructor new Object usually the shortcut object literal {} is used
Instead of setting the values in the hashMap to 1 one might use true; you also could omit the equality operator == and just check for the truthiness of the property. I even would use the in operator.
function validatePassTimeFields(passtimes) {
var length = passtimes.length;
var hashMap = {};
for (var j=0; j<length; j++) {
if (passtimes[j].value in hashMap) {
alert("Duplicate Found");
return false;
}
hashMap[passtimes[j].value] = 1;
}
return true;
}
// You would only need to optimize it if you want to use it elsewhere-
function noduplicates(array){
var next, O= {},
L= array.length;
while(L){
next= array[--L];
if(O[next]) return false;
O[next]= 1;
}
return true;
}
function validatePassTimeFields(passtimes){
if (noduplicates(passtimes)) return true;
alert("Duplicate Found");
return false;
}
It might be worth checking out underscore's implementation of this functionality. If you are just looking to eliminate dupes, you can use _.uniq(), but if you are more interested in just knowing that there are dupes or the pure implementation details, you might enjoy checking out the source of this method, which is very nicely documented.
I know this isn't a direct code answer to the question - there are a few here already so it wouldn't be useful to repeat. But I thought it was worth mentioning as underscore is a great utility library and the source is a great place to learn more about well-written javascript.
It seems that you do not want to find the duplicates, only to see if there are any?
You're pretty close, here's a working function;
var hasDuplicates = function (arr) {
var _store = {};
for (var i = 0; i < arr.length; i++) {
if (typeof _store["_" + arr[i]] !== "undefined") {
return true;
}
_store["_" + arr[i]] = true;
}
return false;
};
The underscores in the associative array are necessary for storing numeric values. The hasDuplicates() function only works objects which have a toString() method.
To check for duplicates;
var yourArray = [1, 5, 7, 3, 5, 6];
if (hasDuplicates(yourArray)) {...
Related
Ok, so I've blocked myself in with a stupid move that is now causing conflict with the jQuery library I am using, and well I should say rather is likely breaking more than just that after the reading I have done. Anyway I was attempting to use the following bit:
Array.prototype.contains = function(v) {
for(var i = 0; i < this.length; i++) {
if(this[i] === v) return true;
}
return false;
};
Array.prototype.unique = function() {
var arr = [];
for(var i = 0; i < this.length; i++) {
if(!arr.contains(this[i])) {
arr.push(this[i]);
}
}
return arr;
}
To get the unique values of an array however, this ended up causing a conflict for jQuery in my cause breaks a lot of things, So how can I get around the forbidden yet tasty idea of using prototype? Specifically in this case of needing to the unique values in an array?
A common way to avoid modifying prototypes of native types is static methods:
Array.unique = function( entity ) {
// do your stuff
};
// example call
var unique = Array.unique( [1, 1, 2, 3] );
Or, to take it one step further, even do something like this
var Arrays = Arrays || {};
Arrays.unique = function( entity ) { /* … */ };
This way you are completely separated from the built-in Array.
Does JavaScript have a convenient way to test if a variable matches one of many values?
This is my code,
function Start()
{
if(number==(0||3||6||8||9||11||13||14||15||18||19||22||23||25||27||28||31||34||43||46||47||49||54||58||59||62||63||68||71||74||75))
{
FirstFunction();
}
if(number==(1||4||5||7||12||16||17||20||21||26||29||32||33||42||45||48||50||51||53||55||56||57||60||61||64||65||67||69||70||73||76))
{
SecondFunction();
}
}
as you can see, I tried to use the "or" operator to check if number equals ANY of the listed. this, unfortunately, did not work. I know I can just code:
if(number==0||number==3||number==6....)
I think there should be an alternative to that, is there?
Thank you in advance.
You should insert all your elements in an array and use arr.indexOf(element)
It will return -1 if the element doesn't exist which you can use for your if logic
This is better than having lot of if statements
var x = new Array(1,7,15,18);
if ( x.indexOf(31) != -1 )
{
// Add your logic here
}
You can write something like this, which looks a bit nicer:
This Array prototype function will allow you check if an element exists in a JS array:
Array.prototype.exists = function (x) {
for (var i = 0; i < this.length; i++) {
if (this[i] == x) return true;
}
return false;
}
Then:
function Start()
{
var values1 =[0,3,6,8,9,11,13,14,15,18,19,22,23,25,27,28,31,34,43,46,47,49,54,58,59,62,63,68,71,74,75];
var values2 = [1,4,5,7,12,16,17,20,21,26,29,32,33,42,45,48,50,51,53,55,56,57,60,61,64,65,67,69,70,73,76];
if( values1.exists(number) )
{
FirstFunction();
} else if ( values2.exists(number) )
{
SecondFunction();
}
}
The array techniques already mentioned are good, e.g., [0, 3, 6, 8].indexOf(number) != -1, but note that not all browsers support .indexOf() on arrays (think older IE). If you have a look at the MDN page on .indexOf() you'll see they've provided an implementation of .indexOf() that you can add to the Array.prototype if it doesn't already exist.
But here's a non-array method that will work in older browsers at least as far back as IE6 without needing to add your own functions or modify the prototype of any built-in objects:
if (/^(0|3|6|8|9|11)$/.test(number)) {
// matched, so do something
}
The regex .text() method is expecting a string, but if you give it a number it'll cope.
I'd probably still recommend the array method, but it can't hurt to have another option.
Hey all, long time read but first time poster. I've tried for the past few days trying to solve a logic problem and am having no luck was hoping some one who is good with recursion logic can help me out.
Basically i want to generate an array that contains arrays of all the nested properties of an object in javascript. For an example:
{a:'b',c:{d:{e:'f',g:'h'}},i:'k'}
should return
[['a'],['c','d','e'],['c','d','g'],['i']]
I've tried doing recursion with various for/while loop but get hopelessly lost in the logic :/
Any help would be appreciated.
If there's a better way to describe my problem please let me know and i'll update this post.
The way I'd do it would be to write the recursive "chain builder" so that it took a callback, so that the callback could build the outer list.
function findChains(obj) {
function chainFrom(chain, obj, atEnd) {
if (typeof obj !== 'object') atEnd(chain);
else {
for (var pn in obj) {
if (obj.hasOwnProperty(pn)) {
chain.push(pn);
chainFrom(chain, obj[pn], atEnd);
--chain.length;
}
}
}
}
var rv = [];
chainFrom([], obj, function(chain) {
rv.push(chain.slice(0));
});
return rv;
}
Possibly that's a little overkill, and the callback could just be hard-coded rather than passed in (and down) as an argument.
There's a way to do it recursively within one function, although I'm not sure whether that's any less overkill than the above method.
var obj = {a:'b',c:{d:{e:'f',g:'h'}},i:'k'};
function dig(obj) {
var temp = [];
if (typeof obj == "object") {
for (var key in obj) {
var a = dig(obj[key]);
if (a.length !== 0) {
for (var i = 0; i < a.length; i++) {
a[i].unshift(key);
temp.push(a[i]);
}
} else {
temp.push([key]);
}
}
}
return temp;
}
var arr = dig(obj);
Here's a working example in jsfiddle that shows what arr winds up containing:
http://jsfiddle.net/VZwaR/1/
It should work fine no matter how deep the associative array is.
This question already has answers here:
JavaScript hashmap equivalent
(17 answers)
Closed 6 years ago.
How can you create the JavaScript/JQuery equivalent of this Java code:
Map map = new HashMap(); //Doesn't not have to be a hash map, any key/value map is fine
map.put(myKey1, myObj1);
map.put(myKey2, myObj2); //Repeat n times
function Object get(k) {
return map.get(k);
}
Edit: Out of date answer, ECMAScript 2015 (ES6) standard javascript has a Map implementation, read here for more info: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
var map = new Object(); // or var map = {};
map[myKey1] = myObj1;
map[myKey2] = myObj2;
function get(k) {
return map[k];
}
//map[myKey1] == get(myKey1);
Just use plain objects:
var map = { key1: "value1", key2: "value2" }
function get(k){
return map[k];
}
function Map() {
this.keys = new Array();
this.data = new Object();
this.put = function (key, value) {
if (this.data[key] == null) {
this.keys.push(key);
}
this.data[key] = value;
};
this.get = function (key) {
return this.data[key];
};
this.remove = function (key) {
this.keys.remove(key);
this.data[key] = null;
};
this.each = function (fn) {
if (typeof fn != 'function') {
return;
}
var len = this.keys.length;
for (var i = 0; i < len; i++) {
var k = this.keys[i];
fn(k, this.data[k], i);
}
};
this.entrys = function () {
var len = this.keys.length;
var entrys = new Array(len);
for (var i = 0; i < len; i++) {
entrys[i] = {
key: this.keys[i],
value: this.data[i]
};
}
return entrys;
};
this.isEmpty = function () {
return this.keys.length == 0;
};
this.size = function () {
return this.keys.length;
};
}
This is an old question, but because the existing answers could be very dangerous, I wanted to leave this answer for future folks who might stumble in here...
The answers based on using an Object as a HashMap are broken and can cause extremely nasty consequences if you use anything other than a String as the key. The problem is that Object properties are coerced to Strings using the .toString method. This can lead to the following nastiness:
function MyObject(name) {
this.name = name;
};
var key1 = new MyObject("one");
var key2 = new MyObject("two");
var map = {};
map[key1] = 1;
map[key2] = 2;
If you were expecting that Object would behave in the same way as a Java Map here, you would be rather miffed to discover that map only contains one entry with the String key [object Object]:
> JSON.stringify(map);
{"[object Object]": 2}
This is clearly not a replacement for Java's HashMap. Bizarrely, given it's age, Javascript does not currently have a general purpose map object. There is hope on the horizon, though: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map although a glance at the Browser Compatability table there will show that this isn't ready to used in general purpose web apps yet.
In the meantime, the best you can do is:
Deliberately use Strings as keys. I.e. use explicit strings as keys rather than relying on the implicit .toString-ing of the keys you use.
Ensure that the objects you are using as keys have a well-defined .toString() method that suits your understanding of uniqueness for these objects.
If you cannot/don't want to change the .toString of the key Objects, when storing and retrieving the entries, convert the objects to a string which represents your understanding of uniqueness. E.g. map[toUniqueString(key1)] = 1
Sometimes, though, that is not possible. If you want to map data based on, for example File objects, there is no reliable way to do this because the attributes that the File object exposes are not enough to ensure its uniqueness. (You may have two File objects that represent different files on disk, but there is no way to distinguish between them in JS in the browser). In these cases, unfortunately, all that you can do is refactor your code to eliminate the need for storing these in a may; perhaps, by using an array instead and referencing them exclusively by index.
var map = {'myKey1':myObj1, 'mykey2':myObj2};
// You don't need any get function, just use
map['mykey1']
If you're not restricted to JQuery, you can use the prototype.js framework. It has a class called Hash: You can even use JQuery & prototype.js together. Just type jQuery.noConflict();
var h = new Hash();
h.set("key", "value");
h.get("key");
h.keys(); // returns an array of keys
h.values(); // returns an array of values
This is so simple I am baffled. I have the following:
var x = 'shrimp';
var stypes = new Array('shrimp', 'crabs', 'oysters', 'fin_fish', 'crawfish', 'alligator');
for (t in stypes) {
if (stypes[t] != x) {
alert(stypes[t]);
}
}
Once the values have iterated it starts returning a dozen functions like
function (iterator, context) {
var index = 0;
iterator = iterator.bind(context);
try {
this._each(function (value) {iterator(value, index++);});
} catch (e) {
if (e != $break) {
throw e;
}
}
return this;
}
What the heck is going on?
Edit: In these scripts I am using http://script.aculo.us/prototype.js and http://script.aculo.us/scriptaculous.js I remember now reading about the way prototype extends arrays and I am betting this is part of it. How do I deal with it?
The for enumeration is going to go over every member of the object you passed it. In this case an array, which happens to have functions as members as well as the elements passed.
You could re-write your for loop to check if typeof stypes[t] == "function" or yada yada. But IMO you are better off just modifying your looping to only elements..
for(var i = 0, t; t = stypes[i]; ++i){
if (t != x) {
alert(t);
}
}
Or
for(var i = 0; i < stypes.length; ++i){
if (stypes[i] != x) {
alert(stypes[i]);
}
}
I wanted to migrate my last comment up to the answer to add the notice of the a caveat for the first type of loop.
from Simon Willison's "A re-introduction to JavaScript"..
for (var i = 0, item; item = a[i]; i++) {
// Do something with item
}
Here we are setting up two variables.
The assignment in the middle part of
the for loop is also tested for
truthfulness - if it succeeds, the
loop continues. Since i is incremented
each time, items from the array will
be assigned to item in sequential
order. The loop stops when a "falsy"
item is found (such as undefined).
Note that this trick should only be
used for arrays which you know do not
contain "falsy" values (arrays of
objects or DOM nodes for example). If
you are iterating over numeric data
that might include a 0 or string data
that might include the empty string
you should use the i, j idiom instead.
you want to do:
for (var i in object) {
if (!object.hasOwnProperty(i))
continue;
... do stuff ...
}
As for..in enumeration iterates over all properties (enumerable or otherwise) that exist on both the object and its prototype chain. The hasOwnProperty check restricts iteration to just those properties on the actual object you want to enumerate.
ES5 makes things a little better for library developers (and help avoid this stuff) but we won't see that ina shipping browser for quite a while :-(
[edit: replacing return with continue. lalalalala ;) ]
Since prototype has extended the array for your convenience you should take advantage of it. Your example could be rewritten as:
var x = 'shrimp';
var stypes = new Array('shrimp', 'crabs', 'oysters', 'fin_fish', 'crawfish', 'alligator');
stypes.without(x).each(alert);
It should be
for (t in stypes) {
if (t != x) {
alert(t);
}
}