define associate array without value - javascript

I have a very large hard coded index array that I would like to easily convert to an associative array so lookups are much quicker.
var arr = ["a", "b", "c"];
right now I am looping through arr and comparing it's values to a value to see if there is a match. Now that I have hundreds of elements it's getting rather slow and it would be faster to have an associative array.
It seems I can't just do
var arr = {"a", "b", "c"};
I can't really add a value since it is too slow.
Sure I could copy the elements to an associate array or sort the array and do a binary search but it would be much easier to just able to assign a default value to the array elements and use the syntax above.
I guess this is not possible though?

var mapLookup = arr.reduce(function (accumalator, value) {
accumalator[value] = true;
return accumalator;
}, {});

Why not:
var arr = {"a":1, "b":1, "c":1};

Converting arrays to associative arrays seems to be the easiest and very fast:
var arr = ["a", "b", "c"];
var arrA = {}; for(var i = 0; i < arr.length; i++) arrA[arr[i]] = 0;
then just use key in arrA for O(1) lookup. (it would be easier to have the ability not have to explicitly supply a value to a key but....)
Essentially
if (key in arrA) ...
replaces
for(var i = 0; i < arr.length; i++) if (key == arr[i]) ...
which essentially is O(n) vs O(n^2) when uses inside a loop.

Most modern browsers support Array.indexOf(). This will return -1 if your search bears no results.
Are you actually having speed issues, or are you just pre-optimizing? The container you should be using is an array. You have an array of elements - they don't associate with any other values, so why put them in a map container?
Also, it sounds like you want a set, where you have a unique set of elements.

Related

How to find all combinations of elements in JavaScript array

I have the following array:
[[A,1,X],[B,2,Y],[C,3,Z]]
I want to be able to get all combinations of the first index of each sub array and then loop through those combinations performing a single task on each. So these are the combinations I'm after (Note I need the combination of the same value as well):
[[A,A],[A,B],[A,C],[B,A],[B,B],[B,C],[C,A],[C,B],[C,C]]
I'd then loop through that and do something with each of the values.
I'm not sure where even to start here so any advice or pointers would be really helpful!
You need to effectively loop through the array twice. Based on what you want you can just statically access the first element each time:
var arr = [['A',1,'X'],['B',2,'Y'],['C',3,'Z']];
var newArr = [];
var length = arr.length;
var curr;
for (var i = 0; i < length; i++) {
curr = arr[i][0];
for (var j = 0; j < length; j++) {
newArr.push([curr, arr[j][0]]);
}
}
console.log(newArr);
Fiddle
Try this:
var data = [['A',1,'X'],['B',2,'Y'],['C',3,'Z']];
function getCombinations(data) {
var combinations = [];
data.forEach(function(first) {
data.forEach(function(second) {
combinations.push([first[0], second[0]]);
});
});
return combinations;
}
console.log(getCombinations(data));
Here is the jsfiddle-demo
Let's decompose the problem. First, let's get extracting the first element of each subarray out of the way:
function get_elts(data, idx) {
return data.map(function(v) { return v[idx]; });
}
So
> get_elts(data, 0) // ['A', 'B', 'C']
Decomposing the problem like this is fundamental to good program design. We don't want to write things which jumble up multiple problems. In this case, the multiple problems are (1) getting the first element of each subarray and (2) finding the combinations. If we write one routine which mixes up the two problems, then we will never be able to re-use it for other things. If our boss comes and says now he wants to find all the combinations of the second element of each subarray, we'll have to cut and paste and create nearly duplicate code. Then we'll be maintaining that code for the rest of our lives or at least until we quit. The rule about factoring is do it sooner rather than later.
Then, create all combinations of any two arrays:
function combinations(arr1, arr2) { //create all combos of elts in 2 arrays by
return [].concat.apply( //concatenating and flattening
[], //(starting with an empty array)
arr1.map( //a list created from arr1
function(v1) { //by taking each elt and from it
return arr2.map( //creating a list from arr2
function(v2) { //by taking each element and from it
return [v1, v2]; //making a pair with the first elt
}
);
};
)
);
}
Normally we would write this more compactly. Let's walk through it:
Array#concat combines one or more things, or elements inside those things if they are arrays, into an array.
Function#apply lets us provide an array that will turn into the argument list of concat.
Array#map creates a parallel array to arr1, which contains...
elements which are two-element arrays based on looping over arr2.
Right, this is not your mother's JavaScript. It's almost a different language from the style where you initialize this and set that and loop over the other thing and return something else. By adopting this style, we end up with code which is more precise, concise, reusable, provably correct, future-friendly, and maybe optimizable.
By future-friendly, I mean among other things ES6-friendly. The above could be rewritten as:
combinations = (arr1, arr2) => [].concat(...arr1.map(v1 => arr2.map(v2 => [v1, v2])));
Get ready guys and girls, this will come up in your job interviews pretty soon now. Time to move on from jQuery.
Now the problem can be expressed as:
var first_elts = get_elts(data, 0);
combinations(first_elts, first_elts);

Get the length of an array within a JSON object

I want to find out how many items are in my JSON object. I have seen many answers but they all deal with a common value to loop through. I am wanting the results to tell me that there are 2 items in this object. Any help would be great!
[{"manager_first_name":"jim","manager_last_name":"gaffigan"}]
You could use Object.keys in newer browsers. It would return an array of all the keys in the object, and that array would have a length property that will tell you how many items there are in the object :
var arr = [{"manager_first_name":"jim","manager_last_name":"gaffigan"}];
var length = Object.keys(arr[0]).length;
FIDDLE
In non-supporting browsers, you have to iterate
var arr = [{"manager_first_name":"jim","manager_last_name":"gaffigan"}];
var i = 0;
for (var key in arr[0]) i++;
FIDDLE
You can do this:
var arr = [{"manager_first_name":"jim","manager_last_name":"gaffigan"}],
length = 0,
obj = arr[0]; // Get first obj from array
for(var k in obj){
if( obj.hasOwnProperty(k) ) {
length++;
}
}
console.log(length); // Shows 2
You should use hasOwnProperty because you can also extend an Object with functions, there could otherwise also be count als keys.
Links:
hasOwnProperty
Try
var jsonArr = [{"manager_first_name":"jim","manager_last_name":"gaffigan"}];
var itemCount = JSON.stringify(jsonArr).split('":"').length - 1;
This is, of course, a rather coarse(and unreliable) way of doing it, but if you just want the item count, this should work like a charm.

Removing the elements from one multidimensional array from another multidimensional array

I'm finding it difficult getting my head around what I think is a pretty simple task. My brain is just fried at the moment and I have a deadline. :(
I need to take all the element arrays from one multidimensional array and remove them from another multidimensional array.
Arr1 = [["Tom", "161"], ["Dick", "29"], ["Harry", "46"], ["Mike", "72"], ["Sally", "11"]];
Arr2 = [["Harry", "46"], ["Mike", "72"], ["Tom", "161"]];
So in this instance I want to take all the element arrays from Arr2 and remove them from Arr1 so that afterward Arr1 would look like this:
Arr1 = [["Dick", "29"], ["Sally", "11"]];
Does that make sense?
EDITx2: Wait, no, ignore that, I was being stupid.
Assuming you always have two elements in the array, and a "unique" element is defined as a combination of the name and the number, you can do something like this:
function(array1, array2) {
var seen = {};
var returnedArray = [];
for(var i = 0; i < array2.length; i++) {
var elements = array2[i];
seen[elements[0] + elements[1]] = true;
//an alternative to the above is to do
//seen[JSON.stringify(elements)] = true;
}
for(var i = 0; i < array1.length; i++) {
var elements = array1[i];
if(!seen[elements[0] + elements[1]]) {
returnedArray.push(elements);
}
//an alternative to the above is to do
//if(!seen[JSON.stringify(elements)]) {
// ...
//}
//
//if you took the alternate approach in the first loop
}
return returnedArray;
}
Since it's all strings you could get creative with string methods and chaining. Probably not the best performance and a bit tricky, but it works:
var arr = [["Tom", "161"], ["Dick", "29"], ["Harry", "46"], ["Mike", "72"], ["Sally", "11"]];
var remove = [["Harry", "46"], ["Mike", "72"], ["Tom", "161"]];
var result = arr
.join('|')
.replace(RegExp(remove.join('|'),'g'),'')
.match(/[^|]+/g)
.map(function(s){ return s.split(',') });
console.log(result); //=> [["Dick","29"],["Sally","11"]]
You could even try using JSON. I wouldn't recommend this for production in any case, just for fun.
Demo: http://jsbin.com/obokuy/1/edit
If you need to put together something quick, then use a nested loop to walk through the elements of Arr2 for each element in Arr1 and do a comparison on each. You can look at the answers to this question for a hint on comparing the inner arrays:
How to check if two arrays are equal with JavaScript?

Getting Length of Object in Javascript / jQuery

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 iterate a loop within another loop, based on the same array, what's the best way to ignore duplicates?

I want to save all combinations of an array. So for
[a, b, c] I want to save
[ab, ac, ba, bc, ca, cb]
I currently use this method:
for (coordinate in coordinates){
for (coordinate2 in coordinates){
if (coordinate != coordinate2){
newposts.push([fbposts[fbpost].id, coordinates[coordinate], coordinates[coordinate2]]);
}
}
}
but it generates a bunch of duplicates. What's the smoothest way to solve this?
You could use a modified bubble sort algorithm:
var result = [],
arr = 'abc'.split('');
// begin the bubble sort loop
for(var i=0,l=arr.length;i<l-1;i++)
for(var j=i+1;j<l;j++)
{
result.push(arr[i]+arr[j]);
result.push(arr[j]+arr[i]);
}
console.log(result); //["ab", "ba", "ac", "ca", "bc", "cb"]
By looping over the array in this way, you do not even need to check if the result is a duplicate, because it doesn't generate any.
Btw, don't use the for..in synthax for looping over arrays because it may have unexpected results.
Add a check before adding to your new array either by custom function or perhaps
array.indexOf(...)
Custom function similar to how jQuery does it:
function inArray(needle, haystack) {
var length = haystack.length;
for(var i = 0; i < length; i++) {
if(haystack[i] == needle) return true;
}
return false;
}
So as you are building your new array of permutations/combinations (been 13+ years since my last stats class), perform a quick check and don't add if true, otherwise add. I believe if you perform an array merge it'll do similar so same performance.
You could take advantage of the fact that you can define a property only once and have something like this:
$(function() {
var arr = ["a","b","c"];
var permutations ={};
$.each(arr, function(index1, val1)
{
$.each(arr, function(index2, val2)
{
permutations[val1+val2] = 0;
});
});
for(var prop in permutations)
{
//in prop you will have your elements: aa,ab...
}
});​
permutations would play the role of a dictionary in this case
The logic of generating the combinations is sub optimal as the run time is n square - see this questions for algorithms of generating combinations of k elements out of an n elements array

Categories

Resources