Hi I have two list of objects that i am trying to get unique objects in new list in my angular 4 component.
IList1 l1=[ {"_id":'a1', "name": "john"},
_id":'a2', "name": "adam"},
_id":'a3', "name": "jenny"}];
IList1 l2=[ {"_id":'a1', "name": "john"},
_id":'b5', "name": "joe"},
_id":'a3', "name": "jenny"}];
I am trying to write a code so that I can get the unique item in new list so
IList1 result=[_id":'b5', "name": "joe"}]
I am following is my code to get the result list
var len1=this.l1.length;
var len2=this.l2.lenth;
Ilist1 result=[];
for(var i=0; i<l1; i++)
{
for(var y=0; y<l2; y++)
{
if(this.l1[i]._id !== this.l2[y]._id)
this.result.push(this.l2[y])
}
}
Code above gives the result which is apposite of what I want basically it spits out the common objects in both lists. I tried to change !== to == still not giving the expected result.
Please let me know how I can fix it to get unique record into the result list. Thanks
This is what is happening with your current code:
This is what your code is doing in english:
For each element of list l1 (for(var i=0; i<l1; i++));
go through list l2 (for(var y=0; y<l2; y++));
if the element of l1 is not on all elements of l2 (if(this.l1[i]._id !== this.l2[y]._id))
add it to the list (this.result.push(this.l2[y]))
So what's wrong there is step 3, which translated into execution we get on the first iteration of the part for loop:
l1[0] !== l2[0] ("a2" !== "a1") // true- result = []
l1[0] !== l2[1] ("a2" !== "b5") // true - result = [{"_id":'b5', "name": "joe"}]
l1[0] !== l2[2] ("a2" !== "a3") // true - result = [{"_id":'b5', "name": "joe"}, {"_id":'a3', "name": "jenny"}]
On the second iteration:
l1[1] !== l2[0] ("a1" !== "a1") // false - result = [{"_id":'b5', "name": "joe"}, {"_id":'a3', "name": "jenny"}, {"_id":'a1', "name": "john"}]
l1[1] !== l2[1] ("a1" !== "b5") // true - result = [{"_id":'b5', "name": "joe"}, {"_id":'a3', "name": "jenny"}, {"_id":'a1', "name": "john"},{"_id":'b5', "name": "joe"}]
l1[1] !== l2[2] ("a1" !== "a3") // true - result = [{"_id":'b5', "name": "joe"}, {"_id":'a3', "name": "jenny"}, {"_id":'a1', "name": "john"},{"_id":'b5', "name": "joe"},{"_id":'b5', "name": "joe"}]
So you can see that your condition is not ok because all other elements that are not equal to the current element under test is going to be added to your list.
So to make the logic simpler let's just concat the 2 arrays and apply the same logic as before only going through the same concatenated list twice and using a boolean that tells you if the element is a duplicate or not:
var l1 = [{
"_id": 'a1',
"name": "john"
},
{
"_id": 'a2',
"name": "adam"
},
{
"_id": 'a3',
"name": "jenny"
}
];
var l2 = [{
"_id": 'a1',
"name": "john"
},
{
"_id": 'b5',
"name": "joe"
},
{
"_id": 'a3',
"name": "jenny"
}
];
var result = [];
var joinedArray = l1.concat(l2);
for (var i = 0; i < joinedArray.length; i++) {
var isDuplicate = false;
for (var y = 0; y < joinedArray.length; y++) {
if (i != y && this.joinedArray[i]._id === this.joinedArray[y]._id)
isDuplicate = true;
}
if (!isDuplicate)
this.result.push(joinedArray[i]);
}
console.log(result)
This solution is not the most efficient or the most logic, but it should be easier to understand since it's closer to your original logic.
I would probably count the objects in a hash keyed to the id. Then filter() & map() that count object for items with a count of 1.
let l1=[ {"_id":'a1', "name": "john"},{"_id":'a2', "name": "adam"},{"_id":'a3', "name": "jenny"}];
let l2=[ {"_id":'a1', "name": "john"},{"_id":'b5', "name": "joe"},{"_id":'a3', "name": "jenny"}];
// make an object that counts the items
// only need to store the last item since you're looking for uniques
let counts = [...l1, ...l2].reduce((obj, item) =>{
if (obj[item._id]) obj[item._id].count++
else obj[item._id] = {count:1, object: item}
return obj
}, {})
// filter that object by count and return the objects
let filtered = Object.values(counts).filter(item => item.count === 1).map(item => item.object)
console.log(filtered)
Related
I have an array that I'm retrieving from an API. The array looks like this:
[{
"name": "Rachel",
"count": 4,
"fon": "46-104104",
"id": 2
},
{
"name": "Lindsay",
"count": 2,
"fon": "43-053201",
"id": 3
},
{
"name": "Michael",
"count": 5,
"fon": "46-231223",
"id": 4
}]
Then I loop through the array to create an array containing only the names.
function buildName(data) {
for (var i = 0; i < data.length; i++) {
nameList.push(data[i].name)
}
}
This also works so far, but I would like to create an array in which each name occurs as often as the object count says.
For example, the name Michael should appear five times in the array and Lindsay twice.
[
"Rachel",
"Rachel",
"Rachel",
"Rachel",
"Lindsay",
"Lindsay",
"Michael",
"Michael",
"Michael",
"Michael"
"Michael"
]
For each object create a new array using count, and then fill it with the name.
If you use flatMap to iterate over the array of objects. It will return a new array of nested objects but then flatten them into a non-nested structure.
const data=[{name:"Rachel",count:4,fon:"46-104104",id:2},{name:"Lindsay",count:2,fon:"43-053201",id:3},{name:"Michael",count:5,fon:"46-231223",id:4}];
const out = data.flatMap(obj => {
return new Array(obj.count).fill(obj.name)
});
console.log(out);
I've upgraded your functions but you can use the map method
function buildName(data){
for (let i = 0; i < data.length; i++){
let numToLoop = data[i].count
let name = data[i].name
for (let z = 0; z < +numToLoop; z++){
nameList.push(name)
}
}
}
Use an inner while loop inside the for loop:
const data = [{
"name": "Rachel",
"count": 4,
"fon": "46-104104",
"id": 2
},
{
"name": "Lindsay",
"count": 2,
"fon": "43-053201",
"id": 3
},
{
"name": "Michael",
"count": 5,
"fon": "46-231223",
"id": 4
}]
function buildName(data){
const result = [];
for (let i = 0; i < data.length; i += 1) {
let item = data[i];
let count = item.count;
while (count > 0) {
result.push(item.name);
count -= 1;
}
}
return result;
}
console.log(buildName(data));
Just add an inner loop with as many iterations as the "count" property in the object:
function buildName(data) {
const nameList = [];
for (var i = 0; i < data.length; i++) {
for (let j = 0; j < data[i].count; j++) {
nameList.push(data[i].name);
}
}
return nameList;
}
For fun
import { pipe } from 'fp-ts/lib/function';
import { chain, replicate } from 'fp-ts/lib/Array';
const arr = ...
const result = pipe(
arr,
chain(i => replicate(i.count, i.name))
);
You can use .flapMap() for that:
const arr = [{ "name": "Rachel", "count": 4, "fon": "46-104104", "id": 2 }, { "name": "Lindsay", "count": 2, "fon": "43-053201", "id": 3 }, { "name": "Michael", "count": 5, "fon": "46-231223", "id": 4 }];
const result = arr.flatMap(({count, name}) => Array(count).fill(name));
console.log(result);
Effectively you turn every element into an array of the the name property repeated count times which is then flattened into a single array.
It can be done via creating an array with repeated names in this way:
Array(count).fill(name)
Then you have to spread it into resulting array.
You can try this one-liner
const getNames = (data) =>
data.reduce(
(names, { name, count }) => [...names, ...Array(count).fill(name)],
[]
)
Note that a pure function is presented here, which is generally the preferred way of writing code. However, updating your example code might look like this
const getNames = (data) =>
data.reduce(
(names, { name, count }) => [...names, ...Array(count).fill(name)],
[]
)
function buildName(data) {
nameList = getNames(data)
}
I'm using this data structure in my Angular project. I'm not sure Angular it does matter, but maybe it has benefits:
const content = [
{
"id": 1, // language id
"name": "english",
"code": "en",
"menus": [
{
"id": 1, // group id
"lang_id": 1,
"name": "Default",
"items": [
{
"id": 2, // item id
"name": "About us",
"menu_id": 1,
"is_hidden": 0,
// ...
},
],
},
// ...
],
},
// ...
]
I know the id of the language, the group and the item too with these variable names:
private lang_id = 1;
private group_id = 1;
private item_id = 2;
In the data structure I have many "languages" with many "groups", and I have many "items" in the "groups".
I tried to use this code, but I think here need to be a better soultion:
let indexLang: number;
let indexGroup: number;
for (let i = 0; i < this.content.length; i++) {
if ( this.content[i].id === this.lang_id) {
indexLang = i;
break;
}
}
for (let i = 0; i < this.content[indexLang].menus.length; i++) {
if ( this.content[indexLang].menus[i].id === this.group_id) {
indexGroup = i;
break;
}
}
// and another for loop to find the item...
Is there a better way to find the is_hidden key-value pair with the least resources?
You are looking for Array.prototype.find.
const content = [
{
"id": 1, // language id
"name": "english",
"code": "en",
"menus": [
{
"id": 1, // group id
"lang_id": 1,
"name": "Default",
"items": [
{
"id": 2, // item id
"name": "About us",
"menu_id": 1,
"is_hidden": 0,
// ...
},
],
},
// ...
],
},
// ...
]
let lang_id = 1;
let group_id = 1;
let item_id = 2;
let language = content.find(item => item.id === lang_id);
let group = language.menus.find(item => item.id === group_id);
let item = group.items.find(item => item.id === item_id);
console.dir(item)
You for sure need to add some error handling for the case that one of the ids does not exists. And you could chain those finds:
try {
let item = content.find(item => item.id === lang_id)
.menus.find(item => item.id === group_id)
.items.find(item => item.id === item_id);
} catch( err ) {
// one of the ids did not exists
}
So, I have data. It is array of objects.
data = [
{
"id": "200",
"price": "5000"
},
{
"id": "137",
"price": "8000"
},
{
"id": "230",
"price": "9000"
},
{
"id": "241",
"price": "9000"
},
{
"id": "78",
"price": "10000"
}
]
json=JSON.parse(data);
I make something like pager.
My code should return nearby (previous and next) elements of original element.
It is not allowed to change order of objects.
I'm trying to do something like
json.indexOf(JSON.parse('{"id":"200","price":"5000"}'))
but it returns -1.
Also json[0]==JSON.parse('{"id":"200","price":"5000"}') return false, but I think that this elements are similar.
What way do you see?
json=JSON.parse('[{"id":"200","price":"5000"},{"id":"137","price":"8000"},{"id":"230","price":"9000"},{"id":"241","price":"9000"},{"id":"78","price":"10000"}]');
console.log(json.indexOf(JSON.parse('{"id":"200","price":"5000"}')));
console.log(json[0]==JSON.parse('{"id":"200","price":"5000"}'));
console.log(json[0]);
console.log(JSON.parse('{"id":"200","price":"5000"}'));
You could take a function which finds the index of the wanted id and returns items before that index, the index and one after the index with adjustment at the beginning of the array.
function getParts(id) {
var index = array.findIndex(o => o.id === id),
min = Math.max(index - 1, 0);
if (index !== -1) {
return array.slice(min, min + (index ? 3 : 2));
}
}
var array = JSON.parse('[{"id":"200","price":"5000"},{"id":"137","price":"8000"},{"id":"230","price":"9000"},{"id":"241","price":"9000"},{"id":"78","price":"10000"}]');
console.log(getParts('200'));
console.log(getParts('137'));
console.log(getParts('230'));
console.log(getParts('78'));
Try this, i think it would work as the 'id' property is unique
var words = [{"id":"200","price":"5000"},{"id":"137","price":"8000"},{"id":"230","price":"9000"},{"id":"241","price":"9000"},{"id":"78","price":"10000"}];
let k;
let sayYourKeyId = "137";
const result = words.find((word, index) => {
if(word.id == sayYourKeyId){
k = index;
}
});
console.log(words[k-1]);
console.log(words[k]);
console.log(words[k+1]);
I've got an array of three people. I want to add a new key to multiple objects at once based on an array of indices. Clearly my attempt at using multiple indices doesn't work but I can't seem to find the correct approach.
var array = [
{
"name": "Tom",
},
{
"name": "Dick",
},
{
"name": "Harry",
}
];
array[0,1].title = "Manager";
array[2].title = "Staff";
console.log(array);
Which returns this:
[
{
"name": "Tom",
},
{
"name": "Dick",
"title": "Manager"
},
{
"name": "Harry",
"title": "Staff"
}
]
But I'd like it to return this.
[
{
"name": "Tom",
"title": "Manager"
},
{
"name": "Dick",
"title": "Manager"
},
{
"name": "Harry",
"title": "Staff"
}
]
You cannot use multiple keys by using any separator in arrays.
Wrong: array[x, y]
Correct: array[x] and array[y]
In your case, it will be array[0].title = array[1].title = "manager";
1st method::
array[0].title = "Manager";
array[1].title = "Manager";
array[2].title = "Staff";
array[0,1] will not work.
2nd method::
for(var i=0;i<array.length;i++) {
var msg = "Manager";
if(i===2) {
msg = "Staff"
}
array[i].title = msg
}
You can use a helper function like this
function setMultiple(array, key, indexes, value)
{
for(i in array.length)
{
if(indexes.indexOf(i)>=0){
array[i][key] = value;
}
}
}
And then
setMultiple(array, "title", [0,1], "Manager");
Try this: `
for (var i=0; var<= array.length; i++){
array[i].title = "manager";
}`
Or you can change it around so var is less than or equal to any n range of keys in the index.
EDIT: instead make var <= 1. The point is to make for loops for the range of indices you want to change the title to.
Assuming that you have a bigger set of array objects.
var array = [
{
"name": "Tom",
},
{
"name": "Dick",
},
{
"name": "Harry",
},
.
.
.
];
Create an object for the new keys you want to add like so:
let newKeys = {
'Manager': [0,2],
'Staff': [1]
}
Now you can add more such titles here with the required indexes.
with that, you can do something like:
function addCustomProperty(array, newKeys, newProp) {
for (let key in newKeys) {
array.forEach((el, index) => {
if (key.indexOf(index) > -1) { // if the array corresponding to
el[newProp] = key // the key has the current array object
} // index, then add the key to the
}) // object.
}
return array
}
let someVar = addCustomProperty(array, newKeys, 'title')
I have a simple task of rearranging a couple of Arrays in a JSON, so ractive.js can handle it better. But I got carried away a bit, and the outcome was not particularly satisfactory.
An example of my initial Array:
[{
"_id": 1,
"type": "person",
"Name": "Hans",
"WorksFor": ["3", "4"],
}, {
"_id": 2,
"type": "person",
"Name": "Michael",
"WorksFor": ["3"],
}, {
"_id": 3,
"type": "department",
"Name": "Marketing"
}, {
"_id": 4,
"type": "department",
"Name": "Sales"
}, {
"_id": 5,
"type": "person",
"Name": "Chris",
"WorksFor": [],
}]
So with a given Department I wanted a method in ractive to give me all Persons who work in this Department (with a list of Departments they work for). Something like:
[{
"_id": 1,
"type": "person",
"Name": "Hans",
"WorksFor": ["3", "4"],
"Readable": ["Marketing", "Sales"]
}, {
"_id": 2,
"type": "person",
"Name": "Michael",
"WorksFor": ["3"],
"Readable": ["Sales"]
}]
The function that somehow came to life was similar to this:
function imsorryforthis() {
let output = [];
let tempdocs = this.get('docs'); //as this happens in a ractive method,
//"this.get" is neccesary for binding
for (var i = 0; i < tempdocs.length; i++) {
if (_.contains(tempdocs[i].WorksFor, givenDepartment)) { //I used underscore.js here
let collectedDepartmentData = [];
if (tempdocs[i].WorksFor.length > 0) {
for (var f = 0; f < tempdocs[i].WorksFor.length; f++) {
for (var g = 0; g < tempdocs.length; g++) {
if (tempdocs[i].WorksFor[f] == tempdocs[g]._id) {
let actualDepartmentData = {};
actualDepartmentData = tempdocs[g];
collectedDepartmentData.push(actualDepartmentData);
}
}
}
}
tempdocs[i].Readable = collectedDepartmentData;
output.push(tempdocs[i]);
}
}
return output;
}
I've put it in a Fiddle as well to make it better readable.
Due to the fact that somehow this monstrosity does work (I was astonished myself), it feels like scratching your left ear with your right hand over your head (while being constantly shouted at by a group of desperate mathematicians).
Maybe anybody knows a more presentable and smarter approach (or a way to compile JavaScript so this never sees the light of day again).
Construct a map department_id => department_name first:
let departments = {};
for (let x of data) {
if (x.type === 'department') {
departments[x._id] = x.Name;
}
}
Then, iterate over Persons and populate Readable arrays from that map:
for (let x of data) {
if (x.type === 'person') {
x.Readable = x.WorksFor.map(w => departments[w]);
}
}
Finally, extract Persons for the specific Department:
personsInSales = data.filter(x =>
x.type === 'person' && x.WorksFor.includes('3'));
Firstly, your data structure does not have a good design. You should not be returning person and department in the same array. If possible, try to redesign the initial data structure to make it more modular, by separating out the people and department into separate structures. However if you are stuck with this same data structure, you can write the code a little better. Please find the code below. Hope it helps!
function mapPeopleDepartment() {
var deptMap = {},peopleList = [];
//Iterate through the initialArray and separate out the department into a hashmap deptMap and people into a new peopleList
for(var i=0; i < initArray.length; i++) {
var obj = initArray[i];
obj.type == "department" ? deptMap[obj._id] = obj.Name : peopleList.push(obj);
}
//Iterate through the peopleList to map the WorksFor array to a Readable array
for(var i=0; i < peopleList.length; i++) {
var person = peopleList[i];
person.Readable = _.map(person.WorksFor, function(dept){return deptMap[dept]});
}
return peopleList;
}