Input array:
["temp/1/Lounge/empty",
"temp/1/Lounge/66,66,66,66,66,66,66,66,64,64,64,64…,64,64,64,64,64,64,64", "temp/2/Lounge/empty",
"temp/3/Lounge/empty"]
I have an array of elements as shown above.
Each item has four parts seperated by ('/').
If first three parts are same and fourth part is different for any two items.I want to remove the item having fourth part as 'empty'.
Example:
If fourth part of element has 'empty' in one item and some data like 66,64,…,64,64,64 in another element.
I want to delete the item having 'empty' as fourth part in the array.
I want output as below:
["temp/1/Lounge/66,66,66,66,66,66,66,66,64,64,64,64…,64,64,64,64,64,64,64",
"temp/2/Lounge/empty",
"temp/3/Lounge/empty"]
I tried to split the array items:
for(i=0;i<arr.length;i++){
stringType = message.split('/')[0];
day = message.split('/')[1] ; //day
room = message.split('/')[2] ;
settingData = message.split('/')[3] ;
}
Please help me to compare items and delete from array.
You can do it as follows:
first, store for every array value in a hash map what "4th values" it has;
next, filter the array and explicitly delete array values of which the 4th value is empty and there are other 4th values (we can check this in the created hash map).
function splitValue(value, ignoreCase) {
let split = value.split('/'),
key = split.slice(0, 3).join('/'),
val = split.slice(3).join('/');
if (ignoreCase) {
key = key.toLowerCase();
}
return [key, val];
}
function filter(arr, ignoreCase = false) {
var byKey = {};
for (let value of arr) {
let [key, val] = splitValue(value, ignoreCase);
if (!byKey.hasOwnProperty(key)) {
byKey[key] = [];
}
if (val !== 'empty') {
byKey[key].push(val);
}
}
return arr.filter((value) => {
let [key, val] = splitValue(value, ignoreCase);
return (val !== 'empty' || byKey[key].length === 0);
});
}
console.log(filter([
"temp/1/Lounge/empty",
"temp/1/Lounge/something",
"temp/2/Lounge/empty",
"temp/3/Lounge/empty"]));
console.log(filter([
"temp/1/Lounge/something",
"temp/3/kitchen/something",
"temp/1/Lounge/empty",
"temp/3/Kitchen/empty"]));
console.log(filter([
"temp/1/Lounge/something",
"temp/3/kitchen/something",
"temp/1/Lounge/empty",
"temp/3/Kitchen/empty"], true));
.as-console-wrapper {
max-height: 100% !important;
}
I also demonstrate in the above example how you can ignore casing of letters, so that temp/3/kitchen/... and temp/3/Kitchen/... are treated as belonging to the same group.
You can use this code. It works perfectly what you need
var resultData = ["temp/1/Lounge/empty", "temp/1/Lounge/66,66,66,66,66,66,66,66,64,64,64,64…,64,64,64,64,64,64,64", "temp/2/Lounge/empty","temp/3/Lounge/empty"];
var data = resultData;
for(var i=0; i<data.length; i++){
var iItem = data[i];
var iFirst = iItem.substring(0, iItem.lastIndexOf("/") + 1);
var iLast = iItem.substring(iItem.lastIndexOf("/") + 1, iItem.length);
for(j=i+1 ; j<data.length; j++){
var jItem = data[j];
var jFirst = jItem.substring(0, jItem.lastIndexOf("/") + 1);
var jLast = jItem.substring(jItem.lastIndexOf("/") + 1, jItem.length);
if(iFirst === jFirst && iLast==='empty'){
resultData.splice(i,1);
}
}
}
console.log(resultData);
You can see that data array is exact copy of resultData array to maintain proper loop when you splice the element from them. For further work around and experimenting the long array values, here is the link to working JSFIDDLE
Related
I have an array of objects called active_filters. It contains a key called value which can contain one or more values (which are separated by commas if there are multiples). I'm trying to remove a certain code from the value key using findIndex. I'm not sure what I'm doing wrong...would appreciate any help. Thanks!
remove_code = "SFMR";
active_filters[0] = {id: "data-type", value: "SFAR,CFAR,IFAR,SFMR,FFAR,PDAR,MCMR,EDMR,CDMR,ECMR,EDAR,CDAR,MDMR", type: "filtered-out-by-car-type"};
Code:
var index = active_filters.findIndex(function(e) { return e.value.split(",").indexOf(remove_code) && e.id === _id });
if (index > -1)
active_filters.splice(index, 1);
Iterate the array with [Array.findIndex()][1] to find the element by id. If the element was found, split the value by comma. Use Array.filter() to remove the code, and join back. Assign the result back to the value property.
var remove_code = "SFMR";
var _id = 'data-type';
var active_filters = [{id: "data-type", value: "SFAR,CFAR,IFAR,SFMR,FFAR,PDAR,MCMR,EDMR,CDMR,ECMR,EDAR,CDAR,MDMR", type: "filtered-out-by-car-type"}];
var index = active_filters.findIndex(function(o) {
return o.id === _id;
});
if(index !== -1) {
active_filters[index].value = active_filters[index].value.split(',').filter(function(s) {
return s !== remove_code;
}).join();
}
console.log(active_filters);
You can do the following with filter(), map(), indexOf() and splice():
var remove_code = "SFMR";
var _id = "data-type";
var active_filters = [{id: "data-type", value: "SFAR,CFAR,IFAR,SFMR,FFAR,PDAR,MCMR,EDMR,CDMR,ECMR,EDAR,CDAR,MDMR", type: "filtered-out-by-car-type"}];
var active_filters = active_filters.filter(i => i.id==_id).map(function(e) {
var temp = e.value.split(",");
var index = temp.indexOf(remove_code);
temp.splice(index,1);
e.value = temp.join();
return e;
});
console.log(active_filters);
You could find the index the slice around it and set that to the value. Create a function that takes in the characters that you want to remove then find the index of those characters. After that you can slice from 0 to the specified index, then from the index + 5 (5 to include the comma) to finish out the remainder of the string. Here's an example of that:
const remove_code = "SFMR";
let active_filters = [];
active_filters.push({id: "data-type", value: "SFAR,CFAR,IFAR,SFMR,FFAR,PDAR,MCMR,EDMR,CDMR,ECMR,EDAR,CDAR,MDMR", type: "filtered-out-by-car-type"});
function removeChars(chars){
const index = active_filters[0].value.indexOf(remove_code);
let newString;
newString = active_filters[0].value.slice(0, index);
newString += active_filters[0].value.slice(index+5);
return newString;
}
active_filters[0].value = removeChars(remove_code);
console.log(active_filters[0]);
I'm trying to remove a certain code from the value key using findIndex.
You're splicing the entire array active_filters, what you need to do is split the filter's value and splice it according the remove_code values. To accomplish that, make a reverse loop and for each match execute the function splice.
Finally, join the values again separating them with comma.
var remove_code = "SFMR",
_id = 'data-type',
active_filters = [{id: "data-type", value: "SFAR,CFAR,IFAR,SFMR,FFAR,PDAR,MCMR,EDMR,CDMR,ECMR,EDAR,CDAR,MDMR", type: "filtered-out-by-car-type"}];
active_filters.forEach(function(f) {
if (f.id === _id) {
var values = f.value.split(','),
length = values.length;
while (length--) if (values[length] === remove_code) values.splice(length, 1);
f.value = values.join();
}
});
console.log(active_filters);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://codepen.io/egomezr/pen/dmLLwP.js"></script>
I've searched SO for a way to do this but most questions only support two arrays (I need a solution for multiple arrays).
I don't want to compare exact objects, I want to compare objects by their ID, as their other parameters may differ.
So here's the example data:
data1 = [{'id':'13','name':'sophie'},{'id':'22','name':'andrew'}, etc.]
data2 = [{'id':'22','name':'mary'},{'id':'85','name':'bill'}, etc.]
data3 = [{'id':'20','name':'steve'},{'id':'22','name':'john'}, etc.]
...
I'd like to return all objects whose ID appears in all arrays, and I don't mind which of the set of matched objects is returned.
So, from the data above, I'd expect to return any one of the following:
{'id':'22','name':'andrew'}
{'id':'22','name':'mary'}
{'id':'22','name':'john'}
Thanks
First, you really need an array of arrays - using a numeric suffix is not extensible:
let data = [ data1, data2, ... ];
Since you've confirmed that the IDs are unique within each sub array, you can simplify the problem by merging the arrays, and then finding out which elements occur n times, where n is the original number of sub arrays:
let flattened = data.reduce((a, b) => a.concat(b), []);
let counts = flattened.reduce(
(map, { id }) => map.set(id, (map.get(id) || 0) + 1), new Map()
);
and then you can pick out those objects that did appear n times, in this simple version they'll all come from the first sub array:
let found = data[0].filter(({ id }) => counts.get(id) === data.length);
Picking an arbitrary (unique) match from each sub array would be somewhat difficult, although picking just one row of data and picking the items from that would be relatively easy. Either would satisfy the constraint from the question.
If you want the unique object by Name
data1 = [{'id':'13','name':'sophie'},{'id':'22','name':'mary'}]
data2 = [{'id':'26','name':'mary'},{'id':'85','name':'bill'}]
data3 = [{'id':'29','name':'sophie'},{'id':'22','name':'john'}]
flattened = [ ...data1, ...data2, ...data3 ];
counts = flattened.reduce(
(map, { name }) => map.set(name, (map.get(name) || 0) + 1), new Map()
);
names = []
found = flattened.filter(({ name }) => {
if ((counts.get(name) > 1) && (!names.includes(name))) {
names.push(name);
return true
}
return false
});
its too many loops but , if u can find the common id which is present in all the arrays then it would make your finding easier i think .you can have one array value as reference to find the common id
var global = [];
for(var i = 0;i<data1.length;i++){
var presence = true;
for(var j=0;j<arrays.length;j++){
var temp = arrays[j].find(function(value){
return data1[i].id == value.id;
});
if(!temp){
presence = false;
break;
}
}
if(presence){
global.push(data1[i].id)
}
}
console.log(global);
var data1 = [{'id':'13','name':'sophie'},{'id':'22','name':'andrew'}];
var data2 = [{'id':'22','name':'mary'},{'id':'85','name':'bill'}];
var data3 = [{'id':'20','name':'steve'},{'id':'22','name':'john'}];
var arrays = [data1, data2, data3];
var global = [];
for(var i = 0;i<data1.length;i++){
var presence = true;
for(var j=0;j<arrays.length;j++){
var temp = arrays[j].find(function(value){
return data1[i].id == value.id;
});
if(!temp){
presence = false;
break;
}
}
if(presence){
global.push(data1[i].id)
}
}
console.log(global);
There's mention you you need n arrays, but also, given that you can:
put all the arrays into an array called data
you can:
combine your arrays
get a list of duplicated IDs (via sort by ID)
make that list unique (unique list of IDs)
find entries in the combined list that match the unique IDs
where the count of those items match the original number of arrays
Sample code:
// Original data
var data1 = [{'id':'13','name':'sophie'},{'id':'22','name':'andrew'}]
var data2 = [{'id':'22','name':'mary'},{'id':'85','name':'bill'}]
var data3 = [{'id':'13','name':'steve'},{'id':'22','name':'john'}]
var arraycount = 3;
// Combine data into a single array
// This might be done by .pushing to an array of arrays and then using .length
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort?v=control
var data = [].concat(data1).concat(data2).concat(data3);
//console.log(data)
// Sort array by ID
// http://stackoverflow.com/questions/840781/easiest-way-to-find-duplicate-values-in-a-javascript-array
var sorted_arr = data.slice().sort(function(a, b) {
return a.id - b.id;
});
//console.log(sorted_arr)
// Find duplicate IDs
var duplicate_arr = [];
for (var i = 0; i < data.length - 1; i++) {
if (sorted_arr[i + 1].id == sorted_arr[i].id) {
duplicate_arr.push(sorted_arr[i].id);
}
}
// Find unique IDs
// http://stackoverflow.com/questions/1960473/unique-values-in-an-array
var unique = duplicate_arr.filter(function(value, index, self) {
return self.indexOf(value) === index;
});
//console.log(unique);
// Get values back from data
//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter?v=control
var matches = [];
for (var i = 0; i < unique.length; ++i) {
var id = unique[i];
matches.push(data.filter(function(e) {
return e.id == id;
}))
}
//console.log(matches)
// for data set this will be 13 and 22
// Where they match all the arrays
var result = matches.filter(function(value, index, self) {
return value.length == arraycount;
})
//console.log("Result:")
console.log(result)
Note: There's very likely to be more efficient methods.. I've left this in the hope part of it might help someone
var arr1 = ["558", "s1", "10"];
var arr2 = ["55", "s1", "103"];
var arr3 = ["55", "s1", "104"];
var arr = [arr1, arr2, arr3];
console.log(arr.reduce((p, c) => p.filter(e => c.includes(e))));
// output ["s1"]
How can I cut the 6th object's value and paste it into the last object? Below is the result of this code :
JSON.parse(json).forEach(function(obj, idx, array) {
console.log(obj);
});
Updated: As you mentioned that if any object has an value must be cut
and moved to the last,
var array = JSON.parse(json),
index;
array.forEach(function(obj, idx) {
if(obj.itemId) {
index = idx;
}
});
if(typeof index !=="undefined") {
var tempObj = array.splice(index,1);
// adding it the end
array.push(tempObj);
}
It will remove the last element with itemId and move it to the end.
If I understand your question, you want to replace the last object with the object with type:"award".
Then I would do it like this:
JSON.parse(json).forEach(function(obj, idx, array) {
if (obj.type === "award") {
array[array.length - 1] = obj;
}
});
if the award is already the last, it will only be overwritten by itself.
Considering that your get an array of objects, iterate through all the objects and you will end up with the last object that has award in its type key.
for(var i = 0, _len = obj.length; i < _len; i += 1) {
if(obj[i].type === "award") {
ourObj = obj[i];
}
}
obj[obj.length-1] = ourObj;
James,
I have some few question just to get my understanding clear before providing an answer.
So, you want to remove the 6th item in array and want to replace that with the last item ?
The item you are going to remove is always going to be 6th item ?
Answer:
var item, items = JSON.parse(json), itemCount = items.length, obj, position;
for (var i = 0; i < itemCount; i++) {
item = items[i];
if (item.itemId) {
position = i;
}
}
if (position) {
items.push(items.splice(position, 1));
}
The code above will make sure that if the item appears at last position will also be handled. If you want to clone the object instead of referencing the old one then you need to loop through the object and update the new one like below
if (position) {
obj = items.splice(position, 1);
item = {};
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
item[property] = obj[property];
}
}
items.push(item);
}
Just filter it:
var res = JSON.parse(json).filter(function(value) {
return value.itemId == 6;
});
Use Array.prototype.splice() to remove the element you want. Push it to the end.
var arr = [];
var tgtIdx = -1;
var lastID = -1;
JSON.parse(json).forEach(function (obj, idx, array) {
if(obj.itemId !== null && obj.itemId > lastID) {
tgtIdx = idx;
lastID = obj.itemId;
}
arr.push(obj);
})
if(tgtIdx >= 0 && tgtIdx < arr.length - 1) {
arr.push(arr.splice(tgtIdx, 1)[0]);
}
I have an array of objects, shown below. The first segment of code is within a loop where multiple objects of 'Item' are created and pushed onto the array.
Example of the problem is available here: http://jsfiddle.net/X6VML/
Notice how changing the value inside a textbox displays a duplicate item.
// class
var Item = function(label, value) {
this.Label = label;
this.Value = value;
};
var obj = new Item("My Label", "My Value");
// adds object onto array
itemArray.push(obj);
The problem I have is that the array can contain duplicate objects which I need to filter out before rending the list of objects into a table, shown below:
for (var i = 0; i < itemArray.length; i++) {
$('.MyTable').append("<tr><td>" + itemArray[i].Label + "</td><td>" + itemArray[i].Value + "</td></tr>");
}
I can identify whether it's a duplicate with the Value being the same. How can I filter the list of objects based on whether the Value already exists in the array?
Many thanks
Just don't add duplicate item in array:
var item = new Item("My Label", "My Value1");
if(!$.grep(itemArray, function(obj) { return obj.Value == item.Value; }).length)
itemArray.push(item);
If there is already an object with Value "My Value1" in itemArray, just don't add it.
A simple solution would be:
var temp = [];
$.each(itemArray, function(index, obj){
var found = false;
$.each(temp, function(tempI, tempObj){
if(tempObj.Value == obj.Value){
found = true;
return false;
}
});
if(!found){
temp.push(obj);
}
});
itemArray = temp;
console.log(itemArray);
The above is simply iterating over each object in the array, and pushing it to the temp array if it's not already there, finally it overwrites itemArray with temp.
Have you considered eliminating duplicates at the point of adding to the array? Something like this:
function UniqueItemList(){
var items = [];
this.push = function(item){
for(var i=0; i<items.length; i++){
if(items[i].Value == item.Value){
return;
}
}
items.push(item);
};
this.getList = function(){
return items;
}
}
var myList = new UniqueItemList();
myList.push(new Item('label1', 'value1'));
myList.push(new Item('label2', 'value2'));
myList.push(new Item('label1', 'value1'));
myList.push(new Item('label1', 'value1'));
console.log(myList.getList());
If you try to push a duplicate item, it will be rejected.
Demo - here it is integrated into your code.
This code would do. Modify the itemArray before forming the HTML.
var arr = {};
for ( var i=0; i < itemArray.length; i++ )
arr[itemArray[i].Value] = itemArray[i];
itemArray = new Array();
for ( key in arr )
itemArray.push(arr[key]);
I've got this handy utility function:
function uniq(ary, key) {
var seen = {};
return ary.filter(function(elem) {
var k = (key || String)(elem);
return seen[k] === 1 ? 0 : (seen[k] = 1);
})
}
where key is a function that fetches the comparison key from an element.
Applied to your use case:
uniqueItems = uniq(itemArray, function(item) { return item.Value })
I need to know if one or more duplicates exist in a list. Is there a way to do this without travelling through the list more than once?
Thanks guys for the suggestions. I ended up using this because it was the simplest to implement:
var names = [];
var namesLen = names.length;
for (i=0; i<namesLen; i++) {
for (x=0; x<namesLen; x++) {
if (names[i] === names[x] && (i !== x)) {alert('dupe')}
}
}
Well the usual way to do that would be to put each item in a hashmap dictionary and you could check if it was already inserted. If your list is of objects they you would have to create your own hash function on the object as you would know what makes each one unique. Check out the answer to this question.
JavaScript Hashmap Equivalent
This method uses an object as a lookup table to keep track of how many and which dups were found. It then returns an object with each dup and the dup count.
function findDups(list) {
var uniques = {}, val;
var dups = {};
for (var i = 0, len = list.length; i < len; i++) {
val = list[i];
if (val in uniques) {
uniques[val]++;
dups[val] = uniques[val];
} else {
uniques[val] = 1;
}
}
return(dups);
}
var data = [1,2,3,4,5,2,3,2,6,8,9,9];
findDups(data); // returns {2: 3, 3: 2, 9: 2}
var data2 = [1,2,3,4,5,6,7,8,9];
findDups(data2); // returns {}
var data3 = [1,1,1,1,1,2,3,4];
findDups(data3); // returns {1: 5}
Since we now have ES6 available with the built-in Map object, here's a version of findDups() that uses the Map object:
function findDups(list) {
const uniques = new Set(); // set of items found
const dups = new Map(); // count of items that have dups
for (let val of list) {
if (uniques.has(val)) {
let cnt = dups.get(val) || 1;
dups.set(val, ++cnt);
} else {
uniques.add(val);
}
}
return dups;
}
var data = [1,2,3,4,5,2,3,2,6,8,9,9];
log(findDups(data)); // returns {2 => 3, 3 => 2, 9 => 2}
var data2 = [1,2,3,4,5,6,7,8,9];
log(findDups(data2)); // returns empty map
var data3 = [1,1,1,1,1,2,3,4];
log(findDups(data3)); // returns {1 => 5}
// display resulting Map object (only used for debugging display in snippet)
function log(map) {
let output = [];
for (let [key, value] of map) {
output.push(key + " => " + value);
}
let div = document.createElement("div");
div.innerHTML = "{" + output.join(", ") + "}";
document.body.appendChild(div);
}
If your strings are in an array (A) you can use A.some-
it will return true and quit as soon as it finds a duplicate,
or return false if it has checked them all without any duplicates.
has_duplicates= A.some(function(itm){
return A.indexOf(itm)===A.lastIndexOf(itm);
});
If your list was just words or phrases, you could put them into an associative array.
var list=new Array("foo", "bar", "foobar", "foo", "bar");
var newlist= new Array();
for(i in list){
if(newlist[list[i]])
newlist[list[i]]++;
else
newlist[list[i]]=1;
}
Your final array should look like this:
"foo"=>2, "bar"=>2, "foobar"=>1