Javascript objects runtime changes - javascript

Okay, I think my problem is a common Javascript thing.
A have a simple ajax call with a success callback.
The ajax call returns a list of products. Now I need a list of these products sorted by Id and sorted by Date.
The list of products contains objects like this one:
{
Id: 12345,
LastModified: "2015-01-05T14:53:18.493Z",
Name: "Beer"
}
Here is my sample code:
var prodsAll;
var prodsNew;
$.ajax({
url:"getProds.php",
success:function(res) {
prodsAll= res;
prodsNew = res;
prodAll.sort(function (a, b) {
return a.Id > b.Id ? 1 : -1;
});
prodNew.sort(function (a, b) {
return new Date(b.LastModified).getTime() - new Date(a.LastModified).getTime();
});
}
});
Whatever I do, it looks that all of my lists are changed!?
When I do:
console.log(res);
console.log(prodsAll);
console.log(prodsNew);
I always get the same result :-/
How is it possible to change the lists independent!?

This is the problem
prodsAll= res;
prodsNew = res;
These have the same reference to a single array, you make a fresh copy of it like this
prodsAll = res;
prodsNew = res.slice();

Related

JSON filtration via map returns results for matches and undefined for non-matches

I have a javascript function that filters JSON data. It looks like this:
var orderInfo = Products.map( function(order) {
if( filter.node.material.value === "Leather"){
var info = { "Title": order.node.title
}
return info;
}
});
console.log(orderInfo);]
This actually works as intended, but for all of the results which do not meet the criteria, they are returned as "undefined". I only want to return the objects which match the filtration though.
Is there a way that I can achieve this?
You should use reduce instead of map:
var orderInfo = Products.reduce((acc, order) => {
if (order.node.material.value === "Leather") {
acc.push({ "Title": order.node.title });
}
return acc;
}, [])
If you don't want to transform the data, and just wanted to return the matching orders, you would use filter:
var orderInfo = Products.filter(order => order.node.material.value === 'Leather')

How to remove duplicates from result returned by Bootstrap-3-Typeahead?

I have integrated Bootstrap3-typeahed in my project and everything works fine. Problem is i have duplicate entries in mysql database which properties i need to read but don't want them to be shown multiple times in autocomplete/suggest drop down.
For example, user types 'bab' in input field results that are shown:
babble
babble
babbler.
Result that i'm trying to achieve is: babble babbler
Here is the code that responds for showing results:
$.ajax({
url:"engine/searchhandler.php",
method:"POST",
data: {query:query, lang:$('#lang-pseudo').val()},
dataType:"json",
async: false,
success:function(data){
result($.map(data, function(item) {
return item;
}))
}
})
I tried to sanitize result in this way but it doesn't seem to work (log shows empty elements):
success:function(data){
result($.map(data, function(item) {
var list = new Array();
var unique = list.filter(function(elem, index, self) {
return index == self.indexOf(elem);
})
console.log(unique);
//return item;
}))
}
Can someone help me to remove duplicates from result?
Use a Set.
If data contains your array:
const withoutDupes = [...new Set(data)];
Sets can only contain unique values. The [...] converts the Set back to an array.
Without Set:
// 'data', not 'list'
const withoutDupes = data.filter(function(elem, index, self) {
return index === self.indexOf(elem);
});

Checking Each Value in For Loop

I've searched for an answer for this but haven't found one that cover this well with a good example.
I have a for loop:
for (var i=0;i<userProfileProperties.length;i++) {
if (userProfileProperties[i].indexOf("ValueImSearchingFor") {
console.log("GOTIT");
}
}
I'm trying to test each value in the loop to see if it contains a certain set of letters. If it doesn't, that value can be dropped. I can't get this to work. I've searched and have found examples but none seem do what I'm trying to do. or at least I've found no "working" example. I'm new to javascript.
So if my values in the loop returned normally would be: Jack User1, Jill User1, and Jerry User2; the values I want returned are all "User1"
I can't get this to work for:
while(userEnumerator.moveNext()){
var oUser = userEnumerator.get_current();
if(oUser.val.indexOf('ValueImsearchingFor') > -1)
{ ... do this} }
Use Array.prototype.filter() method available for arrays as below:
ES5
var res = userProfileProperties.filter(function (val) {
return val.indexOf("ValueImSearchingFor") > -1
});
ES6
let res = userProfileProperties.filter((val) => {
return val.indexOf("ValueImSearchingFor") > -1
});
let userProfileProperties = [
'ValueImSearchingFor 1',
'ValueImSearchingFor 2',
'test',
'ValueImSearchingFor 3',
'test 1'
];
let res = userProfileProperties.filter((val) => {
return val.indexOf("ValueImSearchingFor") > -1
});
console.log(res);

jQuery object .sort() not sorting

I'm trying to sort a list by it's value but I can't figure out why it doesn't work once I changed it.
The nothing is sorted once I change the a and b part to ipArray[a/b.value].
I can confirm that all the option values exists in the ipArray as I'm able to get those values by using selectList.each(function(){
alert( ipArray[$(this).val()].ipAdd)
)
ipArray is an array that has objects of this format
{
ipAdd : "",
network : ""
}
id = id of the entry
eg. ipArray[id] = { ip : "1.2.3.4", network: "test network"};
// Example
var id = $("#list");
var selectList = $("option", id );
selectList.sort(function (a, b) {
a = a.value;
b = b.value;
// Doesn't work. Would like to sort by network name then by ip address
//a = ipArray[a.value].ipAdd;
//b = ipArray[b.value].ipAdd;
return a - b;
});
id.html(selectList);
Edit:
Created a fiddle https://jsfiddle.net/bme4rv6o/12/
With the expected output
You are sorting using a property value which doesn't even exists in the object
selectList.sort(function (a, b) {
var _network = a.network.localCompare(b.network);
var _ip = a.ip.localCompare(b.ip);
// Will first check network, if equal will then check IP
return (_network==0?_ip:_network);
});
First, note that a.value is a string. Parse it to int and subtract 1 from it to then use the result as the index.
Finally, use localeCompare to sort strings, instead of subtracting.
Fiddle: https://jsfiddle.net/bme4rv6o/13/
Also, you'll probably need to add more logic to sort function to handle a tie (EG, when both a and b are equal, return an IP comparison (which would also need proper parse for each token separated by the dots)).
Simply one line of code:
It evaluates the first part and if the network is the same, then the other part is evaluated.
selectList.sort(function (a, b) {
return a.network.localeCompare(b.network) || a.ipAdd.localeCompare(b.ipAdd);
});
The algorithm is working fine, see below. But your selectList does contain an object, whicht is not sortable like you would like.
var ipArray = [];
function add(ip, network) {
ipArray.push({ ip: ip, network: network });
}
add("1.1.1.1", "A");
add("2.2.2.2", "B");
add("3.3.3.3", "D");
add("4.4.4.4", "C");
add("5.5.5.5", "A");
ipArray.sort(function (a, b) {
return a.network.localeCompare(b.network) || a.ip.localeCompare(b.ip);
});
document.write('<pre>' + JSON.stringify(ipArray, 0, 4) + '</pre>');

Reconstruct JSON after duplicates have been removed

I have the following JSON -
{
"node1":[
{
"one":"foo",
"two":"foo",
"three":"foo",
"four":"foo"
},
{
"one":"bar",
"two":"bar",
"three":"bar",
"four":"bar"
},
{
"one":"foo",
"two":"foo",
"three":"foo",
"four":"foo"
}
],
"node2":[
{
"link":"baz",
"link2":"baz"
},
{
"link":"baz",
"link2":"baz"
},
{
"link":"qux",
"link2":"qux"
},
]
};
I have the following javascript that will remove duplicates from the node1 section -
function groupBy(items, propertyName) {
var result = [];
$.each(items, function (index, item) {
if ($.inArray(item[propertyName], result) == -1) {
result.push(item[propertyName]);
}
});
return result;
}
groupBy(catalog.node1, 'one');
However this does not account for dupicates in node2.
The resulting JSON I require is to look like -
{
"node1":[
{
"one":"foo",
"two":"foo",
"three":"foo",
"four":"foo"
},
{
"one":"bar",
"two":"bar",
"three":"bar",
"four":"bar"
}
],
"node2":[
{
"link":"baz",
"link2":"baz"
},
{
"link":"qux",
"link2":"qux"
},
]
};
However I cannot get this to work and groupBy only returns a string with the duplicates removed not a restructured JSON?
You should probably look for some good implementation of a JavaScript set and use that to represent your node objects. The set data structure would ensure that you only keep unique items.
On the other hand, you may try to write your own dedup algorithm. This is one example
function dedup(data, equals){
if(data.length > 1){
return data.reduce(function(set, item){
var alreadyExist = set.some(function(unique){
return equals(unique, item);
});
if(!alreadyExist){
set.push(item)
}
return set;
},[]);
}
return [].concat(data);
}
Unfortunately, the performance of this algorithm is not too good, I think somewhat like O(n^2/2) since I check the set of unique items every time to verify if a given item exists. This won't be a big deal if your structure is really that small. But at any rate, this is where a hash-based or a tree-based algorithm would probably be better.
You can also see that I have abstracted away the definition of what is "equal". So you can provide that in a secondary function. Most likely the use of JSON.stringify is a bad idea because it takes time to serialize an object. If you can write your own customized algorithm to compare key by key that'd be probably better.
So, a naive (not recommended) implementation of equals could be somewhat like the proposed in the other answer:
var equals = function(left, right){
return JSON.stringify(left) === JSON.stringify(right);
};
And then you could simply do:
var res = Object.keys(source).reduce(function(res, key){
res[key] = dedup(source[key], equals);
return res;
},{});
Here is my version:
var obj = {} // JSON object provided in the post.
var result = Object.keys(obj);
var test = result.map(function(o){
obj[o] = obj[o].reduce(function(a,c){
if (!a.some(function(item){
return JSON.stringify(item) === JSON.stringify(c); })){
a.push(c);
}
return a;
},[]); return obj[o]; });
console.log(obj);//outputs the expected result
Using Array.prototype.reduce along with Array.prototype.some I searched for all the items being added into the new array generated into Array.prototype.reduce in the var named a by doing:
a.some(function(item){ return JSON.stringify(item) === JSON.stringify(c); })
Array.prototype.some will loop trough this new array and compare the existing items against the new item c using JSON.stringify.
Try this:
var duplicatedDataArray = [];
var DuplicatedArray = [];
//Avoiding Duplicate in Array Datas
var givenData = {givenDataForDuplication : givenArray};
$.each(givenData.givenDataForDuplication, function (index, value) {
if ($.inArray(value.ItemName, duplicatedDataArray) == -1) {
duplicatedDataArray.push(value.ItemName);
DuplicatedArray.push(value);
}
});

Categories