jQuery/JS: Sorting array based upon another array? - javascript

I want to sort a JSON object/array (shown below as myArray), upon values from another array - very close to the MYSQL query MYSQL WHERE IN(1,2,3). I was able to get a great answer by Nick Craver on how to sort by one property and value, but how can I do this with multiple values from my other array?
Here's my dataset Json array:
var myArray = [
{
"id":"2",
"name":"My name",
"properties":{"prop1":"value1"}
}];
And the array which I want to sort upon (serialized, coming straight from a form):
var sortArray = [ { "prop1":"value1","prop2":"value2" }];
The current sorting function as it looks right now (courtesy Nick Craver):
function filterDataset(property, value){
var newArray = [];
for (var i = 0, l = myArray.length; i < l; i++) {
if (myArray[i].properties[property] === value)
newArray.push(myArray[i]);
}
return newArray;
}

Here's how I managed to fix it:
function filterDataset2(properties){
var newArray = [];
for (var i = 0, l = dataset.length; i < l; i++) {
$.each(properties, function(){
if (dataset[i].properties[this.name] === this.value)
newArray.push(myArray[i]);
});
}
return newArray;
}

This may not be what you mean, but if you have a known list of properties, could you just || your comparison? Say you have 2 properties...
function filterDataset(property, value){
var newArray = [];
for (var i = 0, l = myArray.length; i < l; i++) {
if ((dataset[i].egenskaper[property1] === value) || (dataset[i].egenskaper[property2] === value) )
newArray.push(myArray[i]);
}
return newArray;
}
Otherwise if the length of the sorting array is unknown you could use a array.find type method that will return true if the property is found within the array in question. If it returns true, just push that value on your newly sorted array.

Related

Find the length of an specific object within an array

In the following code there is a console log of obj['mn'] which returns the length of that specific object which is 2. The problem with the code is that it doesn't count the multidimentional array, and only it counts the first array. The result should be 4 because there are 4 'mn' in total. What am I doing wrong?
var arr = [['ab','pq','mn','ab','mn','ab'],'mn','mn'];
var obj = { };
for (var i = 0, j = arr.length; i < j; i++) {
if (obj[arr[i]]) {
obj[arr[i]]++;
}
}
console.log(obj['mn']);
This is what you're looking for:
var arr = [['ab','pq','mn','ab','mn','ab'],'mn','mn'];
var obj = { };
function count(arr, obj) {
for (var i = 0, j = arr.length; i < j; i++) {
if (Array.isArray(arr[i])) {
count(arr[i], obj);
}
else if (typeof obj[arr[i]] !== 'undefined') {
obj[arr[i]]++;
}
else {
obj[arr[i]] = 1;
}
}
return obj;
}
console.log(count(arr, obj));
This is a recursive implementation. When it gets to an array, the recursion get one level deeper.
You are calling obj[['ab','pq','mn','ab','mn','ab']], which is obviously not what you wanted.
You need a depth first search.
If arr[i] is an array, then you need to loop through that array.

Combine object value

My jquery array is showing like
[Object { qty=1, item_id="76", add_ons="2", add_on_price:20}, Object { qty=1, item_id="76", add_ons="1",add_on_price:40}]
I want to make an array like this
[object{ qty=2,item_id=76,add_ons_price=60}]
I need to add the qty,add_ons_price in single object.
any help will be appreciated.
this will group objects based on property item_id
var result = {};
for (var i = 0, len = myObjects.length; i < len; i++) {
var obj = myObjects[i];
if (result[obj.item_id] === undefined) {
result[obj.item_id] = [];
}
result[obj.item_id].push(obj);
}
now you can add the required values and push the result in new object

Count how many strings in an array have duplicates in the same array [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Array value count javascript
I have an array which contains several duplicates, what I'm trying to achieve is to count how many duplicates each unique string has in this one array.
The array looks something like this
array = ['aa','bb','cc','aa','ss','aa','bb'];
Thus I would like to do something like this
if (xWordOccurrences >= 5) {
// do something
}
But I'm not sure how I would code this.
I was thinking, create an object with each unique string, then loop through the original array, match each string with it's object and increment it's number by 1, then loop over the object to see which words had the most duplicates...
But this seems like an over complexe way to do it.
You can use an object which has keys of the Array's values and do something like this
// count everything
function getCounts(arr) {
var i = arr.length, // var to loop over
obj = {}; // obj to store results
while (i) obj[arr[--i]] = (obj[arr[i]] || 0) + 1; // count occurrences
return obj;
}
// get specific from everything
function getCount(word, arr) {
return getCounts(arr)[word] || 0;
}
getCount('aa', ['aa','bb','cc','aa','ss','aa','bb']);
// 3
If you only ever want to get one, then it'd be more a bit more efficient to use a modified version of getCounts which looks similar to getCount, I'll call it getCount2
function getCount2(word, arr) {
var i = arr.length, // var to loop over
j = 0; // number of hits
while (i) if (arr[--i] === word) ++j; // count occurance
return j;
}
getCount2('aa', ['aa','bb','cc','aa','ss','aa','bb']);
// 3
Try this function:
var countOccurrences = function(arr,value){
var len = arr.length;
var occur = 0;
for(var i=0;i<len;i++){
if(arr[i]===value){
occur++;
}
}
return occur;
}
var count = countOccurrences(['aaa','bbb','ccc','bbb','ddd'],'bbb'); //2
If you want, you can also add this function to the Array prototype:
Array.prototype.countOccurrences = function(value){
var len = this.length;
var occur = 0;
for(var i=0;i<len;i++){
if(this[i]===value){
occur++;
}
}
return occur;
}
How about you build an object with named property?
var array = ['aa','bb','cc','aa','ss','aa','bb'];
var summary = {};
var item = '';
for ( i in array){
item = array[i];
if(summary[item]){
summary[item] += 1;
}
else{
summary[item] = 1;
}
}
console.log( summary );
summary will contain like this
{aa: 3, bb: 2, cc: 1, ss: 1}
which you could then iterate on and then sort them later on if needed.
finally to get your count, you could use this summary['aa']
<script type="text/javascript">
var array = ['aa','bb','cc','aa','ss','aa','bb'];
var myMap = {};
for(i = 0; i < array.length; i++) {
var count = myMap[array[i]];
if(count != null) {
count++;
} else {
count = 1;
}
myMap[array[i]] = count;
}
// at this point in the script, the map now contains each unique array item and a count of its entries
</script>
Hope this solves your problem
var array = ['aa','bb','cc','aa','ss','aa','bb'];
var dups = {};
for (var i = 0, l = array.length; i < l; i++ ) {
dups[array[i]] = [];
}
for (str in dups) {
for (var i = 0, l = array.length; i < l; i++ ) {
if (str === array[i]) {
dups[str].push(str);
}
}
}
for (str in dups) {
console.log(str + ' has ' + (dups[str].length - 1) + ' duplicate(s)');
}
This function may do everything you need.
function countDupStr(arr, specifier) {
var count = {}, total = 0;
arr.forEach(function (v) {
count[v] = (count[v] || 0) + 1;
});
if(typeof specifier !== 'undefined') {
return count[specifier] - 1;
}
Object.keys(count).forEach(function (k) {
total += count[k] - 1;
});
return total;
}
Each value in the array is assigned and incremented to the count object. Whether or not a specifier was passed, the function will return duplicates of that specific string or the total number of duplicates. Note that this particular technique will only work on string-coercible values inside your arrays, as Javascript can only index objects by string.
What this means is that during object assignment, the keys will normalize down to strings and cannot be relied upon for uniqueness. That is to say, this function wouldn't be able to discern the difference between duplicates of 3 and '3'. To give an example, if I were to perform:
var o = {}, t = {};
o[t] = 1;
console.log(o);
The key used in place of t would eventually be t.toString(), thus resulting in the perhaps surprising object of {'[object Object]': 1}. Just something to keep in mind when working with Javascript properties.
I saw this post about it, perhaps it can help:
http://ryanbosinger.com/blog/2011/javascript-count-duplicates-in-an-array/

Remove duplicate element pairs from multidimensional array

I have an array that looks like this:
1. coordinates = [ [16.343345, 35.123523],
2. [14.325423, 34.632723],
3. [15.231512, 35.426914],
4. [16.343345, 35.123523],
5. [15.231512, 32.426914] ]
The latitude on line 5 is the same as on line 3, but they have different longitudes and are therefore not duplicates.
Both the latitude and longitude are the same on line 3 and 6, and are therefore duplicates and one should be removed.
The difficulty in this question that different arrays never compare equal even if they contain same values. Therefore direct comparison methods, like indexOf won't work.
The following pattern might be useful to solve this. Write a function (or use a built-in one) that converts arrays to scalar values and checks if these values are unique in a set.
uniq = function(items, key) {
var set = {};
return items.filter(function(item) {
var k = key ? key.apply(item) : item;
return k in set ? false : set[k] = true;
})
}
where key is a "hash" function that convert items (whatever they are) to comparable scalar values. In your particular example, it seems to be enough just to apply Array.join to arrays:
uniqueCoords = uniq(coordinates, [].join)
You can use standard javascript function splice for this.
for(var i = 0; i < coordinates.length; i++) {
for(var j = i + 1; j < coordinates.length; ) {
if(coordinates[i][0] == coordinates[j][0] && coordinates[i][1] == coordinates[j][1])
// Found the same. Remove it.
coordinates.splice(j, 1);
else
// No match. Go ahead.
j++;
}
}
However, if you have thousands of points it will work slowly, than you need to consider to sort values at first, then remove duplicates in one loop.
I rewrote the answer from thg435 (It does not allow me to post comments) and prototype it also using jQuery instead, so this will work on all browsers using it (Even IE7)
Array.prototype.uniq = function (key) {
var set = {};
return $.grep(this, function (item) {
var k = key
? key.apply(item)
: item;
return k in set
? false
: set[k] = true;
});
}
You can use it like:
arr = arr.uniq([].join);
If you are not on Safari this single liner could do the job
var arr = [[16.343345, 35.123523],
[14.325423, 34.632723],
[15.231512, 35.426914],
[16.343345, 35.123523],
[15.231512, 32.426914]],
lut = {},
red = arr.filter(a => lut[a] ? false : lut[a] = true);
document.write("<pre>" + JSON.stringify(red,null,2) + "</pre>");
It might be simpler to create another array keeping only unique coordinate pairs
var uniqueCoors = [];
var doneCoors = [];
for(var x = 0; x < coordinates.length; x++) {
var coorStr = coordinates[x].toString();
if(doneCoors.indexOf(coorStr) != -1) {
// coordinate already exist, ignore
continue;
}
doneCoors.push(coorStr);
uniqueCoors.push(coordinates[x]);
}
function sortCoordinates(arr){
var obj = {};
for(var i = 0, l = arr.length; i < l; i++){
var el = arr[i];
var lat = el[0];
var lng = el[1];
if(!obj[lat + lng]){
obj[lat + lng] = [lat, lng];
}
}
var out = [];
for(p in obj){
out.push([obj[p][0], obj[p][1]]);
}
return out;
}
I am not sure about coordinates[][] dataType. Make the comparison accordingly.
var dubJRows= new Array();
for(int i = 0; i < coordinates.length -2; i++){
for(int j = i+1; j < coordinates.length -1; j++){
if (i != j && chk_dubJRows_not_contains(j)) {
innerArray1 [1][1] = coordinates[i];
innerArray2 [1][1] = coordinates[j];
if ( innerArray1 [1][0] == innerArray2[1][0]
&& innerArray1[1][1] == innerArray2[1][1]) {
dubJRows.push(j);
}
}
}
}
//REMOVE ALL dubJRows from coordinates.

Building an object graph from flat object array in javascript

i have a javascript array of objects with objects that look like this:
itemId
name
parentItemId <== top level items with no parent have null value
I want to build a graph where the parent items contain arrays of children and those children have arrays of children if applicable.
What is a good way to go about this?
function objectGraph(items)
{
var items_by_id = {};
var roots = [];
var i;
// Build an id->object mapping, so we don't have to go hunting for parents
for (i = 0; i < items.length; ++i) {
items_by_id[items[i].itemId] = items[i];
items[i].children = [];
}
for (i = 0; i < items.length; ++i) {
var parentId = items[i].parentItemId;
// If parentId is null, this is a root; otherwise, it's parentId's kid
var nodes = (parentId === null) ? roots : items_by_id[parentId].children;
nodes.push(items[i]);
}
return roots;
}
Note, this code gives every node a children property, that's empty if a node has no kids. I personally find it simpler and more consistent than each node maybe-or-maybe-not having children; you can loop over children without worrying whether it exists. A leaf node will have children.length == 0.
If you can guarantee you have exactly one root, you can return roots[0]; instead of returning the array.
When you build a "tree builder function" you have to decide if the "top level thing" is a single item or an array of items. Since you said itemS we go with an array. The difference is the parameter you pass in and get returned back, if its an array we pass the parentId, otherwise we pass the id.
function buildTree(parentId, list) {
var nodes = [];
for (var i=0, l; l = list[i]; i++) {
if (l.parentId === parentId) {
// if you need "myList" intact afterwards remove the next line at the cost of efficiency
list.splice(i, 1); i--;
nodes.push({
id: l.id
,parentId: l.parentId
,name: l.name
,children: buildTree(l.id, list)
});
}
}
return nodes;
}
var myTree = buildTree(null, myList);
This is a little rough, but it should do the job if I'm gathering your question correctly. It should return an array of top level objects that have their children correctly organized below them.
As a note, this will work for an N-level of children objects, and not just a single level.
var finalArray = [];
var YOUR_RAW_ARRAY = [];
var buildObjectGraph = function(inputArray){
var i = 0, len = inputArray.length;
var returnVal = [];
for(;i<len;i++){
if(inputArray[i].parentItemId === null){
findChildren(inputArray[i], inputArray);
returnVal.push(inputArray[i]);
}
}
var findChildren = function(root){
var i = 0, i2 = 0, len = rawDataArray.length, len2 = 0;
for(;i<len;i++){
if(inputArray[i].parentItemId === root.itemId){
if(root.children){
root.children.push(inputArray[i]);
}else{
root.children = [];
root.children.push(inputArray[i]);
}
}
}
//now call it recursively
len2 = root.children.length;
if(len2 > 0){
for(;i2 < len2; i2++){
findChildren(root.children[i2]);
}
}
};
return returnVal;
};
//Then execute it
finalArray = buildObjectGraph(YOUR_RAW_ARRAY);

Categories