Checking duplicate in an array that contains objects as an array - javascript

I want to check if there exists duplicate outputTypeId in the output array object..
Below is the JSON:
$scope.entities= [
{
"input": {
"id": 134
},
"output": [
{
"id": 135,
"outputTypeId": 4
}
]
},
{
"input": {
"id": 134
},
"output": [
{
"id": 135,
"outputTypeId": 7
}
]
},
{
"input": {
"id": 134
},
"output": [
{
"id": 135,
"outputTypeId": 9
}
]
}
]
Below is the code that I tried but its not going inside the condition after execution..
Let outputTypeId be [7] as I'm checking for multiple outputTypeId's,hence an array
$scope.checkForDuplicateOutputs = (outputTypeId) => {
for (var i = 0; i < $scope.entities.length; i++) {
for (var j = i; j < $scope.entities[i].output[j].length; j++) {
if (outputTypeId.contains($scope.entities[i].output[j].outputTypeId)) {
$scope.isDuplicateOutput = true;
break;
} else {
$scope.isDuplicateOutput = false;
}
}
}
}

function checkForDuplicates(outputTypeIds) {
$scope.isDuplicateOutput = $scope.entities.some(function(entity) { // Loop through entities
return entity.output.some(function(entityOutput) { // Look for any output
return outputTypeIds.indexOf(entityOutput.outputTypeId) != -1; // which is duplicated in 'outputTypeIds'
});
});
}
So this solution uses Array.some - It has a few advantages:
Removes the need to manually break your loops
No need to have i and j variables to keep track of loop counters
No need to duplicate $scope.isDuplicateOutput = <boolean>;
Less lines of code :)

You are breaking only the inner loop with that break statement and the problem is even though the duplicate flag does get set to true, it will be reset to false in the next iteration. Basically, in the end you'll get the result of the last iteration only.
The quickest fix is to use a flag to denote whether the external loop needs to be stopped:
$scope.checkForDuplicateOutputs = (outputTypeId) => {
var breakOut = false; // <--- this is new
for (var i = 0; i < $scope.entities.length; i++) {
if (breakOut) break; // <--- this is new
for (var j = i; j < $scope.entities[i].output[j].length; j++)
if (outputTypeId.contains($scope.entities[i].output[j].outputTypeId)) {
$scope.isDuplicateOutput = true;
breakOut = true; // <--- this is new
break;
} else {
$scope.isDuplicateOutput = false;
}
}
}
}
If you still want to iterate all the entities and have a list of all the duplicates, you can make $scope.isDuplicateOutput an array and just push the duplicate ids into it.

Related

loop array of objects and add obj for missing entries

I am doing a particular task but it isnt dynamic. Below i have a eventList and a response from API. Based on the eventList, i have to rearrange the response and sort it.
For eg. below, i have eventList XM1, XM2, XM3, So i have to rearrange response, in such a way that eventTitle with XM1 becomes first element, eventTitle with XM2 is second element and XM3 is third element. And this will repeat till the last element of response is reached. In Below example, once id 1, 3, 2 are pushed sequentially object id 4 is left. But id with object 4 has eventTitle XM2. That means XM1 has to be filled with empty object and XM3 has to be filled with another empty object.
let eventList = [ "XM1", "XM2", "XM3" ];
let response = [
{ "id": 1, "eventTitle": "XM1" },
{ "id": 2, "eventTitle": "XM3" },
{ "id": 3, "eventTitle": "XM2" },
{ "id": 4, "eventTitle": "XM2" },
]
The result of this sequentially placing elements and filling the gaps with id=0 is shown below.
let sortResponse = [
{ "id": 1, "eventTitle": "XM1" },
{ "id": 2, "eventTitle": "XM2" },
{ "id": 3, "eventTitle": "XM3" },
{ "id": 0, "eventTitle": "XM1" },
{ "id": 4, "eventTitle": "XM2" },
{ "id": 0, "eventTitle": "XM3" },
]
Here is the code i use to sequentially sort elements and add empty objects in the output. But this is not dynamic. i always knew that my eventList will be 3 elements. but i want to make it dynamic so that even if my eventList is 10 elements, i should be able to sort and fill missing objects in it. Can someone please let me know how to achieve this dynamically
let sortResponse = []
if (eventList.length === 3 && response.length > 0) {
let fil1 = response.filter(function (el) {
return el.eventTitle === eventList[0];
});
let fil2 = response.filter(function (el) {
return el.eventTitle === eventList[1];
});
let fil3 = response.filter(function (el) {
return el.eventTitle === eventList[2];
});
let obj = { id: 0, eventTitle: "" };
let obj1 = { id: 0, eventTitle: "" };
//check if fil1 has most elements and use it to iterate through each fil1 and push fil2 and fil3
if (fil1.length >= fil2.length && fil1.length >= fil3.length) {
for (let j = 0; j < fil1.length; j++) {
sortResponse.push(fil1[j]);
if (!fil2[j]) {
obj.eventTitle = eventList[1];
}
sortResponse.push(fil2[j] ? fil2[j] : obj);
if (!fil3[j]) {
obj1.eventTitle = eventList[2];
}
sortResponse.push(fil3[j] ? fil3[j] : obj1);
}
}
//check if fil2 has most elements and use it to iterate through each fil2 and push fil1 and fil3
else if (fil2.length >= fil1.length && fil2.length >= fil3.length) {
for (let j = 0; j < fil2.length; j++) {
if (!fil1[j]) {
obj.eventTitle = eventList[0];
}
sortResponse.push(fil1[j] ? fil1[j] : obj);
sortResponse.push(fil2[j]);
if (!fil3[j]) {
obj1.eventTitle = eventList[2];
}
sortResponse.push(fil3[j] ? fil3[j] : obj1);
}
}
//check if fil3 has most elements and use it to iterate through each fil3 and push fil1 and fil2
else if (fil3.length >= fil1.length && fil3.length >= fil2.length) {
for (let j = 0; j < fil3.length; j++) {
if (!fil1[j]) {
obj.eventTitle = eventList[0];
}
sortResponse.push(fil1[j] ? fil1[j] : obj);
if (!fil2[j]) {
obj1.eventTitle = eventList[1];
}
sortResponse.push(fil2[j] ? fil2[j] : obj1);
sortResponse.push(fil3[j]);
}
}
}
This isn't particularly optimized since we're "finding" the next element over and over again in our loop, but it's pretty dynamic so it might work for you.
WARNING: This also will NOT terminate if your initial response object contains an event with an event title that is not in the eventList array. In that case, the loop will execute indefinitely and will just keep adding "filler" events to the new response array.
let eventList = [ "XM1", "XM2", "XM3" ];
let response = [
{ "id": 1, "eventTitle": "XM1" },
{ "id": 2, "eventTitle": "XM3" },
{ "id": 3, "eventTitle": "XM2" },
{ "id": 4, "eventTitle": "XM2" },
]
let newResponse = [];
let i = 0;
while(true) {
// Get the event title we are looking for. We'll have to manage looping through event titles kind of manually.
let currentEventTitle = eventList[i];
// Grab the index of the NEXT event that matches the current event title.
let nextEventIndex = response.findIndex( event => event.eventTitle === currentEventTitle );
// If our response has an event that matches, return that event from the current response array, otherwise we'll construct a "filler" event
let nextEvent = nextEventIndex !== -1 ? response.splice(nextEventIndex, 1)[0] : { "id": 0, "eventTitle": currentEventTitle };
// Push the found or constructed event to a new array.
newResponse.push(nextEvent);
// Now we'll need to manage our eventlist looping and exit condition.
// First increment our eventList index or start again from 0 if we've reached the end.
i++;
if(i === eventList.length) i = 0;
// Our exit condition is 1) if our starting response array is empty and 2) if we've gotten to the end of our event list
// which at this point means we've looped back around and our index is 0 again.
if(response.length === 0 && i === 0) break;
}
document.getElementById("result").innerText = JSON.stringify(newResponse, null, 4);
<pre id="result"></pre>

How can I check if a value exists in an array with multiple objects - javascript?

So my array looks like this:
let array = [
{"object1":1},
{"object2":2},
{"object3":3}
];
What I want to do is to check, for example, whether or not "object1" exists. The way I would prefer is pure Javascript.
I am doing this for large chunks of data and so my code needs to be something like this:
if ("opensprint1" in array){
console.log("yes, this is in the array");
} else {
console.log("no, this is not in the array");
};
NOTE: I have tried to use the (in) function in JS and the (hasOwnProperty) and neither has worked.
Any ideas?
if ("opensprint1" in array){
That check for the array keys, so it would work with:
if ("0" in array){
But actually you want to check if some of the array elements got that key:
if(array.some( el => "opensprint1" in el))
You're trying to filter an array of objects. You can pass a custom function into Array.prototype.filter, defining a custom search function. It looks like you want to search based on the existence of keys. If anything is returned, that key exists in the object array.
let array = [{
"object1": 1
},
{
"object2": 2
},
{
"object3": 3
}
];
const filterByKey = (arr, keyName) =>
array.filter(obj => Object.keys(obj).includes(keyName)).length > 0;
console.log(filterByKey(array, 'object1'));
console.log(filterByKey(array, 'object5'));
That is roughly equivalent to:
let array = [{
"object1": 1
},
{
"object2": 2
},
{
"object3": 3
}
];
const filterByKey = (arr, keyName) => {
// iterate each item in the array
for (let i = 0; i < arr.length; i++) {
const objectKeys = Object.keys(arr[i]);
// take the keys of the object
for (let j = 0; j < objectKeys.length; j++) {
// see if any key matches our expected
if(objectKeys[i] === keyName)
return true
}
}
// none did
return false;
}
console.log(filterByKey(array, 'object1'));
console.log(filterByKey(array, 'object5'));
This might help you
let array = [
{"object1":1},
{"object2":2},
{"object3":3}
];
let targetkey = "opensprint1";
let exists = -1;
for(let i = 0; i < array.length; i++) {
let objKeys = Object.keys(array[i]);
exists = objKeys.indexOf(targetkey);
if (exists >= 0) {
break;
}
}
if (exists >= 0) {
console.log("yes, this is in the array");
} else {
console.log("no, this is not in the array");
}
let array = [
{ "object1": 1 },
{ "object2": 2 },
{ "object3": 3 }
];
let checkKey = (key) => {
var found = false;
array.forEach((obj) => {
if (!(obj[key] === undefined)) {
found = true;
array.length = 0;
}
});
return found;
}
console.log(checkKey("object2"));
In this case, I think one of the most efficient way is to do a for and break like:
let array = [
{"object1":1},
{"object2":2},
{"object3":3}
];
exist = false;
for(let i = 0; i<array.length; i++){
if("object1" in array[i]){
exist = true;//<-- We just know the answer we want
break;//<-- then stop the loop
}
}
console.log(exist);
When iteration finds a true case, stops the iteration. We can't perform a break in .map, .filter etc. So the number of iterations are the less possible. I think this is also the case of .some()

To merge two object in to a single. I have this array

To merge two object in to a single. I have this array
var input= [
{
code:"Abc",
a:10
},
{
code:"Abc",
a:11
},
{
code:"Abcd",
a:11
}
]
I need Output as
[
{code:"Abc",a:[10,11]},
{code:"Abcd",a:[11]},
]
Please help
function merge(anArray){
var i, len = anArray.length, hash = {}, result = [], obj;
// build a hash/object with key equal to code
for(i = 0; i < len; i++) {
obj = anArray[i];
if (hash[obj.code]) {
// if key already exists than push a new value to an array
// you can add extra check for duplicates here
hash[obj.code].a.push(obj.a);
} else {
// otherwise create a new object under the key
hash[obj.code] = {code: obj.code, a: [obj.a]}
}
}
// convert a hash to an array
for (i in hash) {
result.push(hash[i]);
}
return result;
}
--
// UNIT TEST
var input= [
{
code:"Abc",
a:10
},
{
code:"Abc",
a:11
},
{
code:"Abcd",
a:11
}
];
var expected = [
{code:"Abc",a:[10,11]},
{code:"Abcd",a:[11]},
];
console.log("Expected to get true: ", JSON.stringify(expected) == JSON.stringify(merge(input)));
You need to merge objects that have the same code, so, the task is simple:
var input = [
{
code:"Abc",
a:10
},
{
code:"Abc",
a:11
},
{
code:"Abcd",
a:11
}
];
// first of all, check at the code prop
// define a findIndexByCode Function
function findIndexByCode(code, list) {
for(var i = 0, len = list.length; i < len; i++) {
if(list[i].code === code) {
return i;
}
}
return -1;
}
var result = input.reduce(function(res, curr) {
var index = findIndexByCode(curr.code, res);
// if the index is greater than -1, the item was already added and you need to update its a property
if(index > -1) {
// update a
res[index].a.push(curr.a);
} else {
// otherwise push the whole object
curr.a = [curr.a];
res.push(curr);
}
return res;
}, []);
console.log('result', result);

Fetch specific array element data using variable [duplicate]

This question already has answers here:
How can I access and process nested objects, arrays, or JSON?
(31 answers)
Closed 7 years ago.
Is there a way to locate data in an array by using value identifiers?
Example: In the object below, I want to do something similar to:
for(country in data.countries)
{
if(country.name === "GB") {return-value-of-country.Clear;}
}
Object example:
{
"countries":[
{
"name": "GB",
"Rain":" url1 ",
"Clear":" url2 "
}
...
]
}
Unless you're using ES6 or some external library there's not a great way to do it, something like:
var countries = data.countries,
len = countries.length,
match, i, country;
for (i = 0; i < len; ++i) {
country = countries[i];
if (country.name === 'GB') {
match = country;
break;
}
}
if (match) {
console.log(match.Clear);
}
To iterate over array you need for loop with index:
for(var i = 0; i<data.countries.length; ++i) {
if(data.countries[i].name === "GB") {
//your value is data.countries[i].Clear;
}
}
If you are not using a library like underscore.
I would do something like:
var test = {
"countries":[
{
"name": "GB",
"Rain":" url1_gb",
"Clear":" url2_gb"
},
{
"name": "FR",
"Rain":" url1_fr",
"Clear":" url2_fr"
},
{
"name": "DE",
"Rain":" url1_de",
"Clear":" url2_de"
},
]
}
var getClearUrl = function(country) {
for (var i = test.countries.length - 1; i >= 0; i--) {
if (test.countries[i].name === country) {
return test.countries[i].Clear;
break;
}
};
return false;
}
var clearUrlGB = getClearUrl('GB');
console.log(clearUrlGB);

Merge json entries with d3

I am making some visualisations and need to merge certain json entries.
The problem is, that the json file that gets called is a bit messed up. Certain entries need to be merged and others should be kept the same.
The json i get is something like this:
[
{
"label": "de",
"visits": 80,
},
{
"label": "fr",
"visits": 80,
},
{
"label": "/de",
"visits": 80,
},
{
"label": "/fr",
"visits": 80,
},
{
"label": "Aktuell",
"visits": 80,
},
{
"label": "fr/Aktuell",
"visits": 80,
},
{
"label": "index",
"visits": 80,
}
]
What i need is:
[
{
"label": "de",
"visits": 160,
},
{
"label": "fr",
"visits": 160,
},
{
"label": "Aktuell",
"visits": 160,
},
{
"label": "index",
"visits": 80,
}
]
The entries with labels "de" and "/de" as well as "fr" and "/fr" or "fr/Aktuell" and "Aktuell" need to be merged while other entries schould be kept the same like "index".
Is there a way to do this using d3?
I guess only using javascript I would have to get the json file, then search for the entries, create a new entry and add up the numbers to then take the original json, delete those entries and add the new entries... although i also wouldn't know exactly how to do that either.
And it also isn't the best solution, since i have to generate a second object that will have to be processed and slows the whole system down. We are having performance issues already and i don't want to create new bottle necks.
Another problem is, that i need to be able to extend the list of entries that should be merged...
Is there a fast and simple way of doing this?
I know this seems like a "hey, i am too lazy, do it for me" post.
I can assure you it isn't. It's more like a " i googled, i read, i tried, i sweared and i cried. now i am asking the professionals for help" post.
UPDATE:
I don't want to filter only on the last part of '/'. It was just an example. The filter would me more like: combine all [en, EN, /en, english, anglais] to one with label en. Also combine all [de, DE, /de, deutsch, german] to one with label de. Keep all others that are not combined.
Javascript should be enough for this:
function clean(arr) {
var obj = {};
// obj will contain a map with keys being 'label' and value being 'visits'
for (var i = 0; i < arr.length; i++) {
var labelParts = arr[i].label.split('/')
var label = labelParts[labelParts.length-1]
// Do a bit of filtering on the label
if(typeof obj[label]!=='undefined') {
obj[label] += arr[i].visits
} else {
obj[label] = arr[i].visits
}
}
return Object.keys(obj).map(function (key) { return {label:key,visits:obj[key]}; });
// Re-create an array out of the object
}
I assumed you wanted to filter on the last part after '/'.
jsFiddle: http://jsfiddle.net/4peN9/2/
I'd look into D3's nest operations. It shouldn't be too hard to specify the appropriate key and rollup functions to get what you want. Something to the effect of:
var cleanup = function(l) {
var i = l.indexOf("/");
return i < 0 ? l : l.substring(i+1, l.length);
};
var getVisits = function(d) { return d.visits; };
var sum = function(a, b) { return a + b; };
var nest = d3.nest()
.key(function(d) { return cleanup(d.label); })
.rollup(function(a) { return a.map(getVisits).reduce(sum); });
jsFiddle: http://jsfiddle.net/4peN9/3/
I now wrote a quite ugly but functional javascript script for this. I am sure that it could be done more efficiently but this shall do for me atm.
And it goes something like this:
function clean(arr)
{
mrgLst = [
{
"valid": "de",
"invalid": ["/de"]
},
{
"valid": "fr",
"invalid": ["/fr"]
},
{
"valid": "en",
"invalid": ["/en"]
},
{
"valid": "it",
"invalid": ["/it"]
},
{
"valid": "/index",
"invalid": ["/index.html"]
}
]
var obj = [];
for (var i = 0; i < mrgLst.length; i++)
{
var valid = mrgLst[i].valid;
var invalid = mrgLst[i].invalid;
for (var j = 0; j < arr.length; j++)
{
var test0 = arr[j].label
if (test0 == valid)
{
var subObj = {};
subObj["label"] = valid
subObj["visits"] = arr[j].visits
for (var k = 0; k < arr.length; k++)
{
var test1 = arr[k].label
for (x in invalid)
{
if (test1 == invalid[x])
{
subObj["label"] = valid
subObj["visits"] += arr[k].visits
}
}
}
}
}
if (subObj != undefined)
{
obj.push(subObj)
}
}
for (var i = 0; i < arr.length; i++)
{
var original = arr[i]
var org = {}
var dont = false
for (var j = 0; j < mrgLst.length; j++)
{
var test0 = mrgLst[j].valid
var test1 = mrgLst[j].invalid
if (original.label == test0)
{
dont = true
}
for (x in test1)
{
if (original.label == test1[x])
{
dont = true
}
}
}
if (dont == false)
{
org["label"] = original.label
org["visits"] = arr[i].visits
obj.push(org)
}
}
return obj
}
Just as reference for anybody that has a similar problem. Doesn't have much to do with d3 anymore but the output is used with d3...

Categories