I am in a situation that feels a little odd ... I have a list of keys deliberately containing duplicates. For the sake of the arguments lets assume this list looks like [1,2,3,2,1]. Currently the code to fetch the documents belonging to these Ids loops over the list of keys, calls findOne() and pushes the document into an array.
So we have a construct like this:
for (var i = 0; i < keys.length; i++) {
documents.push(db.items.findOne(keys[i]);
}
I am wondering whether there is a way to do this in a more ... elegant ... fashion, preferably with a single query? Keeping the order would be a plus but is not strictly required.
Edit:
Please note that this is a MongoDB question. I am looking for a way to substitute the above loop with a single call to db.items.find().
I don't think there's a direct way to retrieve a list for duplicate keys, but since you said that keys are unique you could do it using $in and some looping:
var keys = [1,2,3,2,1];
var docHash = {}; //auxiliary hashtable containing mapping id -> document
var documents = []; //the result
db.items.find({id : {$in : keys}})
.forEach(
function(doc) {
//if multiple documents can have the same key change it to:
// if (docHash[doc.id]) {
// docHash[doc.id].push(doc);
// } else {
// docHash[doc.id] = [doc];
// }
docHash[doc.id] = doc;
});
keys.forEach(function(i) {
// if multiple documents can have the same key change it to:
// docHash[i].forEach(function(item) {documents.push(item);});
documents.push(docHash[i]);
}
Note that, while it's longer than the original, it queries the database only once. As a bonus it returns documents in the same order as the given keys.
use for-each function in java-script that should help you a bit:
for (var i in keys) {// i will be 1 ,2 ,3 ,3 ,1
documents.push(db.items.findOne(i);
}
or i might've missed your questions intention complety?
but then again duplicate keys do not exist in any array..
var used=Array();
for (var i = 0; i < keys.length; i++) {
if (!used[keys[i]]){
used[keys[i]]=1;
documents.push(db.items.findOne(keys[i]);}
}
that will ignore any duplicates and count them as one eather that or you can run query on the keys rendering them in to a new array that does not contains duplicates
Related
While working on building a list of sheet names, I came across this question:
List names of sheets in Google Sheets and skip the first two
Saving you the click, this person's solution is: (Stripped down, pseudo code)
getSheets() // Get all the sheets in spreadsheet workbook
var out = new Array( sheets.length+1 ) ;
for (var i = 1 ; i < sheets.length+1 ; i++ )
out[i] = [sheets[i-1].getName()];
return out
My solution would have leveraged:
...
var sheetName = sheet[i].getName();
out.push(sheetName);
The first solution seems to dynamically create empty array values, then later declare their value. While I have always just pushed new values into the array.
What is the difference?
In which situations is one better than the other?
In which situations should either be avoided?
Your code and the original code do quite different things.
Assuming sheets has objects in it that return the names "sheet1", "sheet2", and "sheet3" from getName, the original code creates an array that looks like this:
[
(missing),
["sheet1"],
["sheet2"],
["sheet3"]
]
Note two things:
There is no entry at index 0. (It literally doesn't exist at all, which is subtly different from existing and containing the value undefined.)
The other entries are single-element arrays, each containing its sheet name.
Your code creates this instead:
[
"sheet1",
"sheet2",
"sheet3"
]
Presumably the author had a reason for skipping index 0 and creating subordinate arrays (I'd guess because they were passing that result array into some API function that expects something in that form).
So there's no really a "better" or "worse" here, just different.
If your fundamental question is whether this:
var original = ["one", "two", "three"];
var updated = [];
for (var i = 0; i < original.length; ++i) {
updated[i] = original[i].toUpperCase(); // Or whatever
}
is better/worse than this:
var original = ["one", "two", "three"];
var updated = [];
for (var i = 0; i < original.length; ++i) {
updated.push(original[i].toUpperCase()); // Or whatever
}
the answer is: It's really a matter of style. Performance isn't markedly different between the two (and rarely matters), and amusingly one way is faster on some JavaScript engines and the other way is faster on others.
Both of those can probably be better expressed using map:
var original = ["one", "two", "three"];
var updated = original.map(function(entry) { return entry.toUpperCase(); });
I think Google Sheets has map, even though it mostly has only ES3-level features otherwise.
Side note: new Array is almost never the right way to create an array.
This is something very basic I might be missing here but I haven't seen such result till now.
I have a for loop where options.headers.length is 3. And in for loop I am dynamically creating a table header. Ideally this loop should run three times for 0 1 and 2 but when I have printed index it's printing 0,1,2,clean and remove. I haven't seen clean and remove as indexes. I know this information is not sufficient enough but if you have any clue please suggest. something might be overriding this is all I am concluded too after my debugging.
for (index in options.headers)
if you don't want to iterate clean and remove then change the loop to:
for (var i=0; i< options.headers.length;i++){
//use i for getting the array data
}
if you use for (index in options.headers) it will iterate for non-numeric keys also.
don use just index (as that is = window.index = global = bad) use var index
(read more here https://www.google.pl/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=globals+javascript+bad)
you have to check does the array has it as own property or maybe its some function (more after answer)
for (var index in options.headers) {
if (options.headers.hasOwnProperty(index) {
// code here
}
}
more about #2:
let's say we have
var array = [0,1,2,3];
and besides that, extending array with function (arrays can have functions in javascript and strings too)
Array.prototype.sayHello = function() {
alert('Hello');
};
then your loop would print sayHello as part of the array, but that's not it's own property, only the arrays
I assume that options.headers is an Array?
This happens when you (or some framework you load) adds methods to the Array prototype. The "for in" loop will enumerate also these added methods. Hence you should do the loop for an array with:
for (var i = 0; i < options.headers.length; i++)
That way you will only get the real values instead of added methods.
I am using expressjs to render my routes and pass on database information.
I have two arrays 1. paintingJobs 2. customerList . The (1) paintingJobs array has a foreign key, which contains the customer ID.I want to create an array of customers who currently HAVE painting jobs and pass that array onto the view. To filter the (2)customerList array down to a list of only those customers who currently have painting jobs; I use a series of nested for loops like so.....
for(var i=0; i<paintingJobs.length; i++) {
for(j=0; j<customerList.length; j++) {
if (customerList[j].ID == paintingJobs[i].CustomerID) {
customerRecords.push(customerList[j]);
}
}
}
Creating the new filtered array of customerRecords, which is then passed to the view.
My Question is: If I sort the (1)paintingJobs array by date prior to using it as a filter for my (1)customerList, will the resulting array (customerRecords) be sorted by date as well or more specifically is this a reliable method? If not, would appending the date to the customerList and then sorting the final array be the next best solution?
I am passing this information to my view and then creating an Unordered List based on the number of records.
Thank you for your time and any suggestions
Your double-loop preserves the order of paintingJobs in customerRecords, though unless you have duplicate customerList ID's, looks somewhat inefficient (why no break?).
This means changes to the order of paintingJobs before your double loop will be reflected in customerRecords. Changes after will not.
paintingJobs.sort(however);
for(var i=0; i<paintingJobs.length; i++) {
for(j=0; j<customerList.length; j++) {
if (customerList[j].ID == paintingJobs[i].CustomerID) {
customerRecords.push(customerList[j]);
break; // next paintingJob
}
}
}
It looks like the items in customerList are Objects, so if you make a change to an Object in customerList, this change will also appear in customerRecords even after your double loop.
This is not a answer to your original question, but concerning performance i would create something like a test- object with the ID as key,like
for(var i=0; i<paintingJobs.length; i++) {
testArray[paintingJobs[i].ID] += 1;
}
for(j=0; j<customerList.length; j++) {
testArray[customerList[j].ID] += 1;
}
and check where the testObject has the value 2.
Then with these keys run your operations.
This method will be MUCH faster as your nested loop.
I have a json object array. I want to search the array and for each object, create a list of 'services' that is a comma-seperated list of all the keys which have a value of "yes".
The list of json objects with the services list is then displayed in html using jquery's each.
Its a large json file so I want to do it as efficiently as possible.
I already have the object's properties being accessed through jQuery's each (ie, obj.name)
-- so I think it should be possible to filter the services listed for each object using
jQuery's filter, and then display the key if the value is yes.
But it seems like a more efficient option would probably be to create a new javascript array, join the services with a value of yes and then add that variable to the html being
appended.
Im not sure which would be faster and so far havent been very successful at either... so any advice and examples would be very helpful.
Here's what the json array looks like:
[
{"name":"name1",
"service1":"y",
"service2":"y",
"service3":"n",
},
{"name":"name2",
"service1":"n",
"service2":"y",
"service3":"n",
},
];
If you just want to filter the array then use grep.
grep - Finds the elements of an array which satisfy a filter function. The original array is not affected.
http://api.jquery.com/jQuery.grep/
First off, delete trailing commas. Internet Explorer gets really, really confused by them. Anyway, I assume you don't want to "search" the array when you say "for each value"; you want to iterate through the array and parse it into a more usable list. The first method I'd suggest is just passing what you want as the array you desire, but if that's not an option, what you're looking for is some variant of this, which should be fairly efficient (jsFiddle example):
var json = [
{"name":"name1", "service1":"y", "service2":"y", "service3":"n"},
{"name":"name2", "service1":"n", "service2":"y", "service3":"n"}
];
var parsed = {};
for (var i = 0, iLen = json.length; i < iLen; i++) {
// Assuming all we need are the name and a list
var name;
var list = [];
for (var key in json[i]) {
var value = json[i][key];
// We need to hold on to the name or any services with value "y"
if (key === "name") {
name = value;
} else if (value === "y") {
list.push(key);
}
}
// Add them to the parsed array however you'd like
// I'm assuming you want to just list them in plain text
parsed[name] = list.join(", ");
}
// List them on the web page
for (var key in parsed) {
document.write(key + ": " + parsed[key] + "<br>");
}
That way you wind up with a display to the visitor of the services available and still keep an array around for further use if necessary.
jQuery.inArray() Search for a specified value within an array and return its index (or -1 if not found).
http://api.jquery.com/jQuery.inArray/
Or
http://api.jquery.com/jQuery.each/
I'm not a javascript guru. I've got the following code below:
var aCookieValues = sCookieContentString.split('&'); // split out each set of key/value pairs
var aCookieNameValuePairs = aCookieValues.split('='); // return an array of each key/value
What I'm trying to do is split the first string via & and then create another array that takes the first array and splits it further via the = character that exists in every value in the aCookieValues array
I get the error aCookieValues.split is not a function.
I've seen an example that basically does the same thing but the second time this guy is using a loop:
(http://seattlesoftware.wordpress.com/2008/01/16/javascript-query-string/)
// '&' seperates key/value pairs
var pairs = querystring.split("&");
// Load the key/values of the return collection
for (var i = 0; i < pairs.length; i++) {
var keyValuePair = pairs[i].split("=");
queryStringDictionary[keyValuePair[0]] = keyValuePair[1];
}
Ultimately what I'm trying to achieve here is a final dictionary with key/value pairs based off the '=' split. I'm simply trying to split up a cookie's values and shove it into a nice dictionary so I can then get certain values out of that dictionary later on.
You are getting this error because aCookieValues is an array, and it does not have a split method. You would need to call the split method on each element of aCookieValues:
var aCookieValues = sCookieContentString.split('&');
for (var i = 0; i < aCookieValues.length; i++) {
var aCookieNameValuePairs = aCookieValues[i].split('=');
// Handle aCookieNameValuePairs[0] as the key
// Handle aCookieNameValuePairs[1] as the value
}
To shove everything in your nice dictionary, simply declare it before the for loop: var myDict = {}, and then put the following after the split('=') call:
myDict[aCookieNameValuePairs[0]] = aCookieNameValuePairs[1];
EDIT: Which, after reading your question properly, is the same method used in the code snippet you supplied. I hope at least this explains how that works :)
In your second line you are attempting to call split() on an array, when it is a function defined on strings.
Example:
"a=1&b=2&c=3".split('&') returns an array ['a=1','b=2','c=3']
Your code would then call split on the array:
['a=1','b=2','c=3'].split('=')
But that function doesn't exist. It seems like your goal is to split each string in the array, so the example you gave in the question seems appropriate - loop through each element and split it.
split operates on a string. You're trying to split aCookieValues, which is an array. The example you cite is looping through the array, and then splitting each element as a string.
Just for fun, one way to deal with this would be to use a map function, which performs an action on each element of an array, and emits an array as a result. If you make a generic map function available to all your arrays, like this:
if (!Array.prototype.map) { // don't step on anyone's toes
Array.prototype.map = function( f ) {
var result = [];
var aLen = this.length;
for( x = 0 ; x < aLen ; x++ ) {
result.push( f(this[x]) );
}
return result;
};
};
...you can call it as a method on your array directly. Thus:
yourstring = 'x=3&y=4&zed=blah&something=nothing';
dictionary = yourstring.split('&').map( function(a){ return a.split('='); } );
dictionary will now be a nice clean array of (arrays of) name/value pairs, like this:
[["x", "3"], ["y", "4"], ["zed", "blahblah"], ["something", "nothing"]]
If your use case becomes complex, an approach like this can be a nice abstraction. Of course, you can arrange these data in other structures if needed, either by playing with a function passed into map, or processing in a separate pass.