How to Splice in a javascript array based on property? - javascript

I am getting an array of data in Angularjs Grid and I need to delete all the rows which has same CustCountry
ex - My Customer Array looks like
Customer[0]={ CustId:101 ,CustName:"John",CustCountry:"NewZealand" };
Customer[1]={ CustId:102 ,CustName:"Mike",CustCountry:"Australia" };
Customer[2]={ CustId:103 ,CustName:"Dunk",CustCountry:"NewZealand" };
Customer[3]={ CustId:104 ,CustName:"Alan",CustCountry:"NewZealand" };
So , in the Grid I need to delete all three records if CustomerCountry is NewZealand
I am using splice method and let me know how can I use by splicing through CustomerCountry
$scope.remove=function(CustCountry)
{
$scope.Customer.splice(index,1);
}

If you're okay with getting a copy back, this is a perfect use case for .filter:
Customer = [
{ CustId:101 ,CustName:"John",CustCountry:"NewZealand" },
{ CustId:102 ,CustName:"Mike",CustCountry:"Australia" },
{ CustId:103 ,CustName:"Dunk",CustCountry:"NewZealand" },
{ CustId:104 ,CustName:"Alan",CustCountry:"NewZealand" },
]
console.log(Customer.filter(cust => cust.CustCountry !== "NewZealand"));

if you have one specific country in mind then just use .filter()
$scope.Customer = $scope.Customer.filter(obj => obj.CustCountry !== "SpecificCountry")
If you want to delete all objects with duplicate countries then, referring to Remove duplicate values from JS array, this is what you can do:
var removeDuplicateCountries = function(arr){
var dupStore = {};
for (var x= 0; x < arr.length; x++){
if (arr[x].CustCountry in dupStore){
dupStore[arr[x].CustCountry] = false;
} else {
dupStore[arr[x].CustCountry] = true;
}
}
var newarr = [];
for (var x= 0; x < arr.length; x++){
if (dupStore[arr[x].CustCountry]){
newarr.push(arr[x]);
}
}
return arr;
};
$scope.Customer = removeDuplicateCountries($scope.Customer);
Or incorporating the .filter() method
var removeDuplicateCountries = function(arr){
var dupStore = {};
var newarr = arr;
for (var x= 0; x < arr.length; x++){
if (arr[x].CustCountry in dupStore){
newarr = newarr.filter(obj => obj.CustCountry !== arr[x].CustCountry);
} else {
dupStore[arr[x].CustCountry] = true;
}
}
return newarr;
};
$scope.Customer = removeDuplicateCountries($scope.Customer);
if there are many duplicate countries then use the way without .filter()

Related

Remove duplicate record by keeping one in object

I have remove duplicate function this will remove duplicate record. But I want atleast one copy of that.
Ex:
var myArr = [{"Country":"China","Rank":"2"},{"Country":"USA","Rank":"2"},{"Country":"China","Rank":"2"}];
O/P = [{"Country":"China","Rank":"2"},{"Country":"USA","Rank":"2"}]
I am deleting on basis of "Country".
My Code
removeDuplicates : function(myArr, Country) {
var finalArray = [];
var values = [];
var value;
for (var i = 0; i < myArr.length; i++) {
value = myArr[i][Country];
if (values.indexOf(value) === -1) {
finalArray.push(myArr[i]);
values.push(value);
}
}
return finalArray;
},
How to maintain original record and remove only duplicate.
Try something like this
var result=[];
myArr.map(function(x){
if(myArr.filter(y=>y.Country==x.Country).length==1 || (result.filter(r=>r.Country==x.Country).length==0))
result.push(x);
})
console.log(result);
I would use reduce & find here.
const myArr = [{"Country":"China","Rank":"2"},{"Country":"USA","Rank":"2"},{"Country":"China","Rank":"2"}];
const newArr = myArr.reduce((prev, cur) => {
if (prev.find((i) => i.Country === cur.Country)) return prev;
prev.push(cur);
return prev;
}, []);

Remove data from an array comparing it to an other array

I am trying to compare the items in "item" array and the copyofOpList array to retrieve the data occurrences in copyofOpList
this is my try:
var _deleteUsedElement1 = function(item) {
for (var i = 0; i < item.length-1; i++){
for (var j = 0; j< $scope.copyofOpList.length-1; j++){
if (item[i].operationCode == $scope.copyofOpList[j].code) {
$scope.copyofOpList.splice(j, 1);
} } } };
$scope.compareArrays = function() {
...Get data from web Service
_deleteUsedElement1(item);
}
the copyofOpList array has 14 elements,and the item array has 2 array
but my code deletes only one occurrence (the first),so please how can I correct my code,to retrieve any occurances in the copyofOpList array comparing to the item array
thanks for help
I'd try to avoid looping inside a loop - that's neither a very elegant nor a very efficient way to get the result you want.
Here's something more elegant and most likely more efficient:
var item = [1,2], copyofOpList = [1,2,3,4,5,6,7];
var _deleteUsedElement1 = function(item, copyofOpList) {
return copyofOpList.filter(function(listItem) {
return item.indexOf(listItem) === -1;
});
};
copyofOpList = _deleteUsedElement1(item, copyofOpList);
console.log(copyofOpList);
//prints [3,4,5,6,7]
}
And since I just noticed that you're comparing object properties, here's a version that filters on matching object properties:
var item = [{opCode:1},{opCode:2}],
copyofOpList = [{opCode:1},{opCode:2},{opCode:3},{opCode:4},{opCode:5},{opCode:6},{opCode:7}];
var _deleteUsedElement1 = function(item, copyofOpList) {
var iOpCodes = item.map(function (i) {return i.opCode;});
return copyofOpList.filter(function(listItem) {
return iOpCodes.indexOf(listItem.opCode) === -1;
});
};
copyofOpList = _deleteUsedElement1(item, copyofOpList);
console.log(copyofOpList);
//prints [{opCode:3},{opCode:4},{opCode:5},{opCode:6},{opCode:7}]
Another benefit of doing it in this manner is that you avoid modifying your arrays while you're still operating on them, a positive effect that both JonSG and Furhan S. mentioned in their answers.
Splicing will change your array. Use a temporary buffer array for new values like this:
var _deleteUsedElement1 = function(item) {
var _temp = [];
for (var i = 0; i < $scope.copyofOpList.length-1; i++){
for (var j = 0; j< item.length-1; j++){
if ($scope.copyofOpList[i].code != item[j].operationCode) {
_temp.push($scope.copyofOpList[j]);
}
}
}
$scope.copyofOpList = _temp;
};

How can I find which index in an array contains an object whose value for a specific key is x? [duplicate]

I would like to find index in array. Positions in array are objects, and I want to filter on their properties. I know which keys I want to filter and their values. Problem is to get index of array which meets the criteria.
For now I made code to filter data and gives me back object data, but not index of array.
var data = [
{
"text":"one","siteid":"1","chid":"default","userid":"8","time":1374156747
},
{
"text":"two","siteid":"1","chid":"default","userid":"7","time":1374156735
}
];
var filterparams = {userid:'7', chid: 'default'};
function getIndexOfArray(thelist, props){
var pnames = _.keys(props)
return _.find(thelist, function(obj){
return _.all(pnames, function(pname){return obj[pname] == props[pname]})
})};
var check = getIndexOfArray(data, filterparams ); // Want to get '2', not key => val
Using Lo-Dash in place of underscore you can do it pretty easily with _.findIndex().
var index = _.findIndex(array, { userid: '7', chid: 'default' })
here is thefiddle hope it helps you
for(var intIndex=0;intIndex < data.length; intIndex++){
eachobj = data[intIndex];
var flag = true;
for (var k in filterparams) {
if (eachobj.hasOwnProperty(k)) {
if(eachobj[k].toString() != filterparams[k].toString()){
flag = false;
}
}
}
if(flag){
alert(intIndex);
}
}
I'm not sure, but I think that this is what you need:
var data = [{
"text":"one","siteid":"1","chid":"default","userid":"8","time":1374156747
}, {
"text":"two","siteid":"1","chid":"default","userid":"7","time":1374156735
}];
var filterparams = {userid:'7', chid: 'default'};
var index = data.indexOf( _.findWhere( data, filterparams ) );
I don't think you need underscore for that just regular ole js - hope this is what you are looking for
var data = [
{
"text":"one","siteid":"1","chid":"default","userid":"8","time":1374156747
},
{
"text":"two","siteid":"1","chid":"default","userid":"7","time":1374156735
}
];
var userid = "userid"
var filterparams = {userid:'7', chid: 'default'};
var index;
for (i=0; i < data.length; i++) {
for (prop in data[i]) {
if ((prop === userid) && (data[i]['userid'] === filterparams.userid)) {
index = i
}
}
}
alert(index);

Best way to group elements in an array with least complexity

I have a JSON array which looks like this:
var map_results = [{"Type":"Flat","Price":100.9},
{"Type":"Room","Price":23.5},
{"Type":"Flat","Price":67.5},
{"Type":"Flat","Price":100.9}
{"Type":"Plot","Price":89.8}]
This array contains about 100,000 records. I want the output to be grouped by "Type" and "Price". It should look like this:
var expected_output = [{"Type":"Flat", "Data":[{"Price":100.9, "Total":2},
{"Price":67.5, "Total":1}] },
{"Type":"Room","Data":[{"Price":23.5,"Total":1}]},
{"Type":"Plot","Data":[{"Price":89.8, "Total:1"}]}]
This has to be done in pure javascript and I cannot use libraries like undersore.js. I tried solving the problem but it had like 3 nested for loops which made the complexity as n^4. What could be a better solution for this problem??
The function I have looks like this:
var reduce = function (map_results) {
var results = [];
for (var i in map_results) {
var type_found = 0;
for(var result in results){
if (map_results[i]["Type"] == results[result]["Type"]){
type_found = 1;
var price_found = 0;
for(var data in results[result]["Data"]){
if(map_results[i]["Price"] == results[result]["Data"][data]["Price"]){
price_found = 1;
results[result]["Data"][data]["Total"] +=1;
}
}
if(price_found == 0){
results[result]["Data"].push({"Price":map_results[i]["Price"], "Total":1});
}
}
}
if(type_found == 0){
results.push({"Type":map_results[i]["Type"], "Data":[{"Price":map_results[i]["Price"],"Total":1}]});
}
}
return results;
};
I have a short function that handles the first part of the requested functionality: It maps the map_results to the desired format:
var map_results = [{"Type":"Flat","Price":100.9},
{"Type":"Room","Price":23.5},
{"Type":"Flat","Price":67.5},
{"Type":"Flat","Price":100.9},
{"Type":"Plot","Price":89.8}]
var expected_output = map_results.reduce(function(obj, current){
if(!obj[current.Type]){
obj[current.Type] = {'Type':current.Type, 'Data':[]};
}
obj[current.Type].Data.push({'Price':current.Price, 'Total':1});
return obj;
},{})
Then this piece of code is required to calculate the totals, I'm afraid:
for(var type in expected_output){
var d = {};
for(var item in expected_output[type].Data){
d[expected_output[type].Data[item].Price] = (d[expected_output[type].Data[item].Price] || 0) + 1;
}
expected_output[type].Data = [];
for(var i in d){
expected_output[type].Data.push({
'Price':i,
'Total':d[i]
})
}
}
Output:
{
"Flat":{
"Type":"Flat",
"Data":[{"Price":"100.9","Total":2},
{"Price":"67.5","Total":1}]
},
"Room":{
"Type":"Room",
"Data":[{"Price":"23.5","Total":1}]
},
"Plot":{
"Type":"Plot",
"Data":[{"Price":"89.8","Total":1}]
}
}
As the Types and the Prices are unique after grouping I think a structure like {"Flat": {"100.9":2,"67.5":1}, {"Room": {"23.5": 1}}} would be easier to handle. So could do the grouping the following way:
var output = {};
map_results.map(function(el, i) {
output[el["Type"]] = output[el["Type"]] || [];
output[el["Type"]][el["Price"] = (output[el["Type"]][el["Price"]+1) || 1;
});
If you can not handle this structure you could do another mapping to your structure.
As you are iterating the Array one time this should have a complexity of n.
Look here for a working fiddle.
EDIT: So remap everything to your structure. The order of the remapping is far less then the first mapping, because the grouping is already done.
var expected_output = [];
for(type in output) {
var prices = [];
for(price in output[type]) {
prices.push({"Price": price, "Total": output[type][price]);
}
expected_output.push({"Type": type, "Data": prices});
}
Below is yet another effort. Here's a FIDDLE
For performance testing, I also mocked up a JSPerf test with 163840 elements. On Chrome(OSX) original solution is 90% slower than this one.
Few notes:
Feel free to optimize for your case (e.g. take out the hasOwnProperty check on object cloning).
Also, if you need the latest Total as the first element use unshift instead of push to add the obj the beginning of the array.
function groupBy(arr, key, key2) {
var retArr = [];
arr.reduce(function(previousValue, currentValue, index, array){
if(currentValue.hasOwnProperty(key)) {
var kVal = currentValue[key];
if(!previousValue.hasOwnProperty(kVal)) {
previousValue[kVal] = {};
retArr.push(previousValue[kVal]);
previousValue[kVal][key] = kVal;
previousValue[kVal]["Data"] = [];
}
var prevNode = previousValue[kVal];
if(currentValue.hasOwnProperty(key2)) {
var obj = {};
for(var k in currentValue) {
if(currentValue.hasOwnProperty(k) && k!=key)
obj[k] = currentValue[k];
}
obj["Total"] = prevNode["Data"].length + 1;
prevNode["Data"].push(obj);
}
}
return previousValue;
}, {});
return retArr;
}
var map_results = [{"Type":"Flat","Price":100.9},
{"Type":"Room","Price":23.5},
{"Type":"Flat","Price":67.5},
{"Type":"Flat","Price":100.9},
{"Type":"Plot","Price":89.8}];
var expected_output = groupBy(map_results, "Type", "Price");
console.dir(expected_output);
Tried something like this:
var reduce_func = function (previous, current) {
if(previous.length == 0){
previous.push({Type: current.Type, Data:[{Price:current.Price,Total:1}]});
return previous;
}
var type_found = 0;
for (var one in previous) {
if (current.Type == previous[one].Type){
type_found = 1;
var price_found = 0;
for(var data in previous[one].Data){
if(current.Price == previous[one].Data[data].Price){
price_found = 1;
previous[one].Data[data].Total += 1;
}
}
if(price_found == 0){
previous[one].Data.push({Price:current.Price, Total:1});
}
}
}
if(type_found == 0){
previous.push({Type:current.Type, Data:[{Price : current.Price ,Total:1}]});
}
return previous;
}
map_results.reduce(reduce_func,[]);

Javascript alphabetical grouping

I have a json array of objects that look like this: {id:'the id', name:'the name'}; and I need to loop over the array and group each object alphabetically by it's name attribute. Is there a way to do this without using a switch / if statement with every letter in it?
What I don't want to do is something like this:
if(data[i].name..slice(0, 1) == 'a') {
...
}
It's a large array, with almost a 1,000 objects in it. My goal is eventually append them to a dive so it looks something like this:
4
4 pints
4 biscuits
A
Apple
Alex
Adam
B
Bob
Billy
you can loop throught your collections like this:
var groupedCollection = {};
for(...){//loop throug collection
var firstLetter = data[i].charAt(0);
if(groupedCollection[firstLetter] == undefined){
groupedCollection[firstLetter] = [];
}
groupedCollection[firstLetter].push(data[i]);
}
//groupedCollection now contait data in the form of {a: [], b:[], etc...}
Bubble sort will do this job for you. Example:
// sample array
var myArr = [
{id:"00", name:"Billy"},
{id:"00", name:"Apple"},
{id:"00", name:"4 biscuits"},
{id:"00", name:"Adam"},
{id:"00", name:"Alex"},
{id:"00", name:"4 pints"},
{id:"00", name:"Bob"}
];
// standard bubble sort algorithm
function bubbleSortByName(arr) {
for (var x = 0; x < arr.length; x++) {
for(var y = 0; y < arr.length-1; y++) {
// compare arr[].name.toLowerCase() i.e. b > a
if(arr[y].name.toLowerCase() > arr[y+1].name.toLowerCase()) {
var tmp = arr[y+1];
arr[y+1] = arr[y];
arr[y] = tmp;
}
}
}
return arr;
}
// sort the array
var sortedArr = bubbleSortByName(myArr);
// print the results
for (var i=0; i<sortedArr.length; i++)
document.write(sortedArr[i].name+"<br/>");
Or the same idea with an insertion sort algorithm:
// standard insertion sort algorithm
function insertionSortByName(arr) {
for(var j = 1; j < arr.length; j++) {
var key = arr[j];
var i = j - 1;
while(i >= 0 && arr[i].name.toLowerCase() > key.name.toLowerCase()) {
arr[i+1] = arr[i];
i = i - 1;
}
arr[i+1] = key;
}
return arr;
}
ES7 syntax
const sortAndGroup = async () => {
const sortedData = data.sort();
const reducedData = sortedData.reduce((items, dataElement) => {
if (!items.find(item => item.header === dataElement.charAt(0))) {
items.push({ header: dataElement.charAt(0) });
}
items.push({ name: dataElement });
return items;
}, []);
return reducedData.map(item => item.header || item.name);
};
sortAndGroup().then(result => console.log(result));

Categories

Resources