Remove duplicates from an array which contains array - javascript

I have a JSON array like this
[{"Email":"someone#some.com","Name":"ACO","Groups":["MOD_SW","MOD_PI","MOD_GE"],"Id":63,"Url":"aco"},
{"Email":"someone#some.com","Name":"Agpo","Groups":["MOD_PI"],"Id":22,"Url":"agpo"},
{"Email":"someone#some.com","Name":"Akatherm","Groups":["MOD_SW"],"Id":64,"Url":"akatherm"},
{"Email":"someone#some.com","Name":"Albrand","Groups":["MOD_PI,"MOD_GE"],"Id":23,"Url":"albrand"}]
I want to create a new array (for select tag) with distinct Groups.
This Groups is an array.
I want that selectbox to have the following values:
MOD_SW
MOD_PI
MOD_GE
My JS:
UpdateSelectMenu: function (selectId, data) {
$(selectId).empty();
$(selectId).html("<option value='all' selected='selected'>All groups</option>");
var array_unique_values = [];
for (var i = 0; i < data.Groups.length; i++) {
for (var j = i+1; j < data.Groups.length; j++) {
if (data.Groups[i] === data.Groups[j]) {
j = ++i;
}
}
array_unique_values.push(data.Groups[i]);
}
array_unique_values = array_unique_values.sort();
$.each(array_unique_values, function (k, v) {
$(selectId).append("<option value='" + v + "'>" + v + "</option>");
});
}
I tried also
for (var i = 0; i < data.length; i++) { //browse whole data
for (var j = 0; j < data[i].Groups.length; j++) { //browse Groups array
for (var k = j + 1; j < data[i].Groups.length; k++) {
if (data[i].Groups[j] === data[i].Groups[k]) {
continue;
}
}
array_unique_values.push(data[i].Groups[j]);
}
}
But error appears as: Groups.length is null or not an object
This code appends to select tag the Group values but it appears as duplicates because Groups is an array.
I have to create a new for statement to browse the Groups array ?
Or there is another alternative to avoid nested for statements ?
Thank you

2 nested loops could do the job:
var data = [... your data ...];
var groups = [];
$.each(data, function(i, item) {
$.each(item.Groups, function(j, group) {
if ($.inArray(group, groups) == -1) {
groups.push(group);
}
});
});
// at this stage groups = ["MOD_SW", "MOD_PI", "MOD_GE"]
and if you wanted to directly append options to your dropdown:
var groups = [];
$.each(data, function(i, item) {
$.each(item.Groups, function(j, group) {
if ($.inArray(group, groups) == -1) {
groups.push(group);
$(selectId).append(
$('<option/>', {
value: group,
text: group
})
);
}
});
});
UPDATE:
And to make this more efficient you could define a static dtstinct method:
$.extend({
distinct : function(arr) {
var result = [];
$.each(arr, function(index, value) {
if ($.inArray(value, result) == -1) {
result.push(value);
}
});
return result;
}
});
and then use the .map method:
var data = [... your data ...];
var groups = $.distinct($(data).map(function() {
return this.Groups;
}));
$.each(groups, function(index, group) {
$(selectId).append(
$('<option/>', {
value: group,
text: group
})
);
});

First look at the last group: "Groups":["MOD_PI,MOD_GE"]
Don't you need to close the quotes after MOD_PI and open them after the comma or this is a set of groups?
If this with the quotes is problem the your script can look something like this:
var obj = [{"Email":"someone#some.com","Name":"ACO", "Groups":["MOD_SW","MOD_PI","MOD_GE"],"Id":63,"Url":"aco"},
{"Email":"someone#some.com","Name":"Agpo", "Groups":["MOD_PI"],"Id":22,"Url":"agpo"},
{"Email":"someone#some.com","Name":"Akatherm", "Groups":["MOD_SW"],"Id":64,"Url":"akatherm"},
{"Email":"someone#some.com","Name":"Albrand", "Groups":["MOD_PI","MOD_GE"],"Id":23,"Url":"albrand"}]
var temp = {},
result = [];
for (var i = 0; i < obj.length; i+=1) {
for (var j = 0; j < obj[i]['Groups'].length; j+=1) {
if (typeof temp[obj[i]['Groups'][j]] === 'undefined') {
result.push(obj[i]['Groups'][j]);
temp[obj[i]['Groups'][j]] = true;
}
}
}
If this is a set of groups:
for (var i = 0; i < obj.length; i+=1) {
for (var j = 0; j < obj[i]['Groups'].length; j+=1) {
currentGroups = obj[i]['Groups'][j].split(',');
for (var k = 0; k < currentGroups.length; k += 1) {
currentGroups[k] = currentGroups[k].replace(/ /g,"");
if (typeof temp[currentGroups[k]] === 'undefined') {
result.push(currentGroups[k]);
temp[currentGroups[k]] = true;
}
}
}
}
I think that's the most efficient way because you're checking for duplicates with O(1) and you don't have to do extra work (for example sort any array).

Related

Flatten Nested Array Without Using Flatten Function

I'm currently stuck on a problem. I'm trying to make [[1,2,[3]],4] -> [1,2,3,4] but cannot get it to work. The output I keep getting is: 1,2,3,4
1,2,3
3
3
3
3..........3
function flattenArray(input) {
var result = [];
console.log(input.toString());
for(i = 0; i < input.length; i++) {
if(input[i].constructor === Array) {
result.push(flattenArray(input[i]));
} else {
result.push(input[i]);
}
}
return result;
}
console.log(flattenArray([[1,2,[3]],4]));
I have this in my common.js file. I use it all the time.
Array.prototype.flatten = function () {
var ret = [];
for (var i = 0; i < this.length; i++) {
if (Array.isArray(this[i])) {
ret = ret.concat(this[i].flatten());
} else {
ret.push(this[i]);
}
}
return ret;
};
Here it is as a function:
function flattenArray(input) {
console.log(input.toString());
var ret = [];
for (var i = 0; i < input.length; i++) {
if (Array.isArray(input[i])) {
ret = ret.concat(flattenArray(input[i]));
} else {
ret.push(input[i]);
}
}
return ret;
}

How to avoid "maximum call stack size exceeded" exception?

I have the next code for generating sitemap tree by urls list.
C# model:
public class Node
{
public Node(string child, string parent)
{
Child = child;
Parent = parent;
}
public string Parent { get; set; }
public string Child { get; set; }
public bool IsRoot { get; set; }
}
C# method that generates list of nodes.
private static List<Node> ExtractNode(List<string> Urls)
{
List<Node> nodeList = new List<Node>();
foreach (string itm in Urls)
{
string[] arr = itm.Split('/');
int index = -1;
foreach (string node in arr)
{
index += 1;
if (index == 0)
{
Node rootNode = new Node(node, "");
if (!nodeList.Exists(x => x.Child == rootNode.Child & x.Parent == rootNode.Parent))
{
rootNode.IsRoot = true;
nodeList.Add(rootNode);
}
}
else
{
Node childNode = new Node(node, arr[index - 1].ToString());
{
if (!nodeList.Exists(x => x.Child == childNode.Child & x.Parent == childNode.Parent))
{
nodeList.Add(childNode);
}
}
}
}
}
return nodeList;
}
Javascript code. Next function takes list of nodes:
function makeTree(nodes) {
var roots = [];
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].IsRoot) {
roots.push(nodes[i].Child);
}
}
var trees = "";
for (var j = 0; j < roots.length; j++) {
trees += "<div class='sitemapRoot'><ul><li>" + getChildren(roots[j], nodes) + "</li></ul></div>";
}
return trees;
}
And next one called recursively:
function getChildren(root, nodes) {
var result = "";
var index = 0;
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].Parent == root) {
index += 1;
}
}
if (index > 0) {
var RootHeader = "";
for (var j = 0; j < nodes.length; j++) {
if (nodes[j].IsRoot & root == nodes[j].Child) {
RootHeader = nodes[j].Child;
}
}
result += RootHeader + "<ul>\n";
for (var k = 0; k < nodes.length; k++) {
if (nodes[k].IsRoot & root == nodes[k].Child) {
RootHeader = nodes[k].Child;
}
if (nodes[k].Parent == root) {
result += "<ul><li>" + nodes[k].Child + getChildren(nodes[k].Child, nodes) + "</li></ul>\n";
}
}
result += "</ul>\n";
return result;
}
return "";
}
This code works good for a small set of data. But when I try to pass list of 500 nodes I get next error:
Uncaught RangeError: Maximum call stack size exceeded
at getChildren (treeGenerator.js:371)
So, the question is how I can optimize code to avoid this error?
There are two ways that you can fix this issue. You always have to worry about the call stack size when you use recursive functions. If you believe it is an issue, then you need to go asynchronous or refactor to not be recursive. These aren't necessarily the most optimized answers but hopefully they'll get you started.
Non-Recursive function
function makeTree(nodes) {
var roots = [],
limbs = [],
i, j;
//go through all of the nodes and link the parent/children.
for (i = 0; i < nodes.length; i++) {
for (j = i + 1; j < nodes.length; j++) {//only look at the rest of the elements to increase performance
if (nodes[i].Child == nodes[j].Parent) {
nodes[i].children = (nodes[i].children || []);
nodes[i].children.push(nodes[j]);
nodes[j].parentNode = nodes[i];
}
}
for (j = 0; j < limbs.length; j++) {//look through the limbs to see if one of them is my child.
if (nodes[i].Child == limbs[j].Parent) {
nodes[i].children = (nodes[i].children || []);
nodes[i].children.push(limbs[j]);
limbs[j].parentNode = nodes[i];
limbs.splice(j--, 1);//remove from the list since I can only have 1 parent.
}
}
//I have all of my children.
if (nodes[i].IsRoot) {
roots.push(nodes[i]);
}else if(!nodes[i].parentNode){
//I don't know my parent so I'm a limb.
limbs.push(node);
}
}
//now that everyone knows their parent and their children, we'll assemble the html by looking at all of the leafs first and working way up the tree.
i = 0;
while(nodes.length > 0){
if(!nodes[i].children || nodes[i].childHtml){
//I'm either a leaf or I have my child's html.
var node = nodes[i];
node.html = node.Child + (node.childHtml? "<ul>" + node.childHtml + "</ul>" : "");
node.childHtml = null;//don't need this anymore.
if(node.parentNode){
//let's check to see if my siblings are complete
var ready = true,
childHtml = "";
for(var j = 0; j < node.parentNode.children.length; j++){
if(node.parentNode.children[j].html == null){
ready = false;//I don't know this html yet so skip it for now.
break;
}else{
childHtml += "<li>" + node.parentNode.children[j].html + "</li>";//go ahead and try to create the list of children.
}
}
if(ready){
//all of siblings are complete, so update parent.
node.parentNode.childHtml = childHtml;
node.parentNode.children = null;//remove reference for cleanup.
}
}
nodes.splice(i, 1);//remove from the list since I have my html.
}else{
i++;//look at the next node in the list.
}
if(i >= nodes.length){
i = 0;//since we are splicing and going through the list multiple times (possibly), we'll set the index back to 0.
}
}
//every node knows it's html, so build the full tree.
var trees = "";
for (var j = 0; j < roots.length; j++) {
trees += "<div class='sitemapRoot'><ul><li>" + roots[j].html + "</li></ul></div>";
}
return trees;
}
Asynchronous Recursive function
function makeTreeAsync(nodes, callback) {
var roots = [],
numRoots = 0;
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].IsRoot) {
numRoots++;
getChildrenAsync(nodes[i], nodes, create);
}
}
function create(child){
roots.push(child);
if(roots.length === numRoots){
var trees = "";
for (var j = 0; j < roots.length; j++) {
trees += "<div class='sitemapRoot'><ul><li>" + roots[j].html + "</li></ul></div>";
}
callback(trees);
}
}
}
function getChildrenAsync(root, nodes, callback) {
var result = "";
var index = 0;
var children = [];
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].Parent == root.Child) {
index += 1;
getChild(i);
}
}
if (index == 0) {
root.html = root.Child;
callback(root);
}
function getChild(x){
setTimeout(function(){
getChildrenAsync(nodes[x], nodes, createHtml);
});
}
function createHtml(node){
children.push(node);
if(children.length === index){
var result = root.Child;
if(children.length){
result += "<ul>"
for (var j = 0; j < children.length; j++) {
result += "<li>" + children[j].html + "</li>";
}
result += "</ul>";
}
root.html = result;
callback(root);
}
}
}
I used the following to create trees for testing the code:
function makeTestNodes(numRoots, numChildrenPerRoot){
var nodes= [];
for(var i = 0;i < numRoots;i++){
nodes.push({
Parent: "",
Child: i.toString(),
IsRoot: 1
});
var parent = i.toString();
for(var j = 0;j < numChildrenPerRoot;j++){
var child = parent + "." + j.toString();
nodes.push({
Parent: parent,
Child: child,
IsRoot: 0
});
nodes.push({
Parent: parent,
Child: parent + "." + j.toString() + "a",
IsRoot: 0
});
parent = child;
}
}
return nodes;
}
Use the following snippet to call the two functions with the test nodes:
Note: the following uses jquery to get the body node. I called the following snippet when the page was ready.
var body = $("body");
body.append(makeTree(makeTestNodes(20, 50)));
makeTreeAsync(makeTestNodes(20, 50), function(html){
body.append(html);
});

JavaScript Json row undefined for TreeView

I have a question. When querying my Json object, although i have my Field as same name and all Json rows available give me an error that is undefined.
//e.g: row.DepParentId
Bellow is my code. Am I missing some tag?
function convert(rows) {
debugger;
function exists(rows, parent) {
for (var i = 0; i < rows.length; i++) {
if (rows[i].DepId === parent) return true;
}
return false;
}
var nodes = [];
// get the top level nodes
for (var i = 0; i < rows.length; i++) {
var row = rows[i];
if (!exists(rows, row.DepParentId)) {
nodes.push({
id: row.DepId,
name: row.Title
});
}
}
var toDo = [];
for (var i = 0; i < nodes.length; i++) {
toDo.push(nodes[i]);
}
while (toDo.length) {
var node = toDo.shift();
// the parent node
// get the children nodes
for (var i = 0; i < rows.length; i++) {
var row = rows[i];
if (row.DepParentId == node.Id) {
var child = {
Id: row.DepId,
Name: row.Title
};
if (node.options) {
node.options.push(child);
} else {
node.options = [child];
}
toDo.push(child);
}
}
}
return nodes;
}
My Json example for one row picked from Firefox
"{"DepId":7,"DepParentId":3,"Title":"OTT"}"
Thanks for helping
Joao
thanks all for helping, it's working now, the problem was the JSON.stringify() was returning only an [Object] so when you use JSON.parse() generates a sintax error.
function onLoaded() {
var itemsCount = items.get_count();
for (var i = 0; i < itemsCount; i++) {
var item = items.itemAt(i);
var dep = JSON.stringify(item.get_fieldValues());
deps.push(dep);
}
So, i had to change the format to be valid to parse like this
var dt = "[" + deps + "]";
var ret = JSON.parse(dt);
Thanks
Joao

Protractor:How to store values in array and then to do sorting

I need to sort list strings under the table ,so for that i have written following lines of code but on console i am not getting any values:
var j = 9;
var rows = element.all(by.repeater('row in renderedRows'));
var column = element.all(by.repeater('col in renderedColumns'));
expect(rows.count()).toEqual(5); //here its printing number of rows
expect(column.count()).toEqual(5); //here its printing number of columns
var arr = [rows.count()];
for (var i = 0; i < rows.count(); i++) {
console.log("aai" + i);
if (i = 0) {
//var columnvalue=column.get(9).getText();
var columnvalue = column.get(9).getText().then(function(ss) {
return ss.trim();
arr[i] = ss.trim(); //here it will save the value first value of column
console.log("value1" + arr[i]);
expect(arr[i]).toEqual('DN');
console.log("aa" + ss.trim());
});
} else {
var j = j + 8;
var columnvalue = column.get(j).getText().then(function(ss) {
return ss.trim();
arr[i] = ss.trim(); //here it will save the other values of column
console.log("value" + arr[i]);
expect(arr[i]).toEqual('DN');
console.log("ab" + ss.trim());
});
}
}
Sorting_Under_Table: function(col){
test = [];
var m;
var dm = 0;
element(by.xpath('//div[#class="ngHeaderScroller"]/div['+col+']')).click();
element.all(by.repeater('row in renderedRows')).then(function(row) {
m = row.length;
for (i = 1; i <= row.length; i++)
{
user_admin_table_name = browser.driver.findElement(by.xpath('//div[#class="ngCanvas"]/div['+i+']/div['+col+']'));
user_admin_table_name.getText().then(function(text) {
var test_var1 = text.toLowerCase().trim();
test.push(test_var1);
var k = test.length
if (k == m){
for (j = 0; j < test.length; j++){
test.sort();
d=j+1;
user_admin_table_name1 = browser.driver.findElement(by.xpath('//div[#class="ngCanvas"]/div['+d+']/div['+col+']'));
user_admin_table_name1.getText().then(function(text1) {
var test_var2 = text1.toLowerCase().trim();
if (test_var2 == test[dm]){
expect(test_var2).toEqual(test[dm]);
dm = dm +1;
}else {
expect(test_var2).toEqual(test[dm]);
log.error("Sorting is not successful");
dm = dm +1;
}
});
}
}
});
}
});
},
You can use this code for sorting and verifying is it sorted or not
I'm not sure how your above example is doing any sorting, but here's a general solution for trimming and then sorting:
var elementsWithTextToSort = element.all(by.xyz...);
elementsWithTextToSort.map(function(elem) {
return elem.getText().then(function(text) {
return text.trim();
});
}).then(function(trimmedTexts) {
return trimmedTexts.sort();
}).then(function(sortedTrimmedTexts) {
//do something with the sorted trimmed texts
});

Remove object from array object Jquery

I am creating array object like follows:
var numberOfSameDeficiency = [];
for (var i = 0; i < result.length; i++) {
var deficiencyId = result[i].Deficiency_Id;
var deficiencyName = result[i].DeficiencyName;
//check to see if this deficiency is already in the list of available selections
if ($("#drpDeficiency option[value='" + deficiencyId + "']").length == 0) {
var option = $('<option>');
option.attr('value', deficiencyId);
option.text(deficiencyName);
$select.append(option);
}
else {
Tests = {};
Tests.TestId = testId;
Tests.DeficiencyId = deficiencyId;
numberOfSameDeficiency.push(Tests);
}
}
And I want to remove object on different function like this:
for (var i = 0; i < result.length; i++) {
console.log(numberOfSameDeficiency);
var isFound = false;
var deficiencyId = result[i].Deficiency_Id;
if (numberOfSameDeficiency) {
numberOfSameDeficiency.forEach(function (entry) {
if (entry.DeficiencyId != deficiencyId) {
isFound = true;
**numberOfSameDeficiency.splice(entry, 1); // Generating Error (Remove all items from array object)**
return;
}
});
// console.log("end if");
}
if (!isFound) {
$("#drpDeficiency option[value='" + deficiencyId + "']").remove();
}
}
So what line code should be there to remove particular object from array object.
Try this
for( i=myArray.length-1; i>=0; i--) {
if( myArray[i].field == "money") myArray.splice(i,1);
}
This also works
myArray = [{name:"Alpesh", lines:"2,5,10"},
{name:"Krunal", lines:"1,19,26,96"},
{name:"Deep",lines:"3,9,62,36" }]
johnRemovedArray = myArray
.filter(function (el) {
return el.name !== "Krunal";
});
Create this prototype function:
Array.prototype.removeElement = function (el) {
for(let i in this){
if(this.hasOwnProperty(i))
if(this[i] === el)
this.splice(i, 1);
}
}
Then call:
let myArray = ['a','b','c','d'];
myArray.removeElement("c");
It also works with objects:
let myObj1 = {name: "Mike"},
myObj2 = {name: "Jenny"},
myArray = [myObj1, myObj2];
myArray.removeElement(myObj2);

Categories

Resources