Mapping the array element with other array - javascript

I have two arrays
array1 = [{id:"1",title:"Writing"},{id:"2",title:"Singing"},{id:"3",title:"Dance"}];
array2 = [{tags: "1",title: "USA",type: "text"},
{tags: "1,2,3",title: "Japan",type: "image"},
{tags: "2,3",title: "Japan",type: "image"}];
I have to map the id of the array1 to tags of the array2 and display the corresponding title from the array1.
The new array2 should look like,
array2=[{tags:"Writing",title:"USA", type:"text"},
{tags: "Writing,Singing,Dance",title: "Japan",type: "image"},
{tags: "Singing,Dance",title: "Japan",type: "image"}];
I did this to get the array1 mapping and got stuck after that.
var newtags= (array1).map(obj=>{
var rObj={};
rObj[obj.id]=obj.title;
return rObj;
});

You can create a mapping object with each id as key and title as value using reduce. Then map over array2 and split each tags to get the new tags
const array1=[{id:"1",title:"Writing"},{id:"2",title:"Singing"},{id:"3",title:"Dance"}],
array2=[{tags:"1",title:"USA",type:"text"},{tags:"1,2,3",title:"Japan",type:"image"},{tags:"2,3",title:"Japan",type:"image"}]
const map = array1.reduce((r, { id, title }) => ({ ...r, [id]: title }), {});
const output = array2.map(({ tags, ...rest }) => {
const newTags = tags.split(',').map(id => map[id]).join(',')
return { tags: newTags, ...rest }
})
console.log(output)
You could also get the mapping object using Object.fromEntries()
const map = Object.fromEntries(array1.map(({ id, title }) => [id, title]));
Then use the regex /\d+(?=,|$)/ to match the numbers and replace them with their respective titles
const array1=[{id:"1",title:"Writing"},{id:"2",title:"Singing"},{id:"3",title:"Dance"}],
array2=[{tags:"1",title:"USA",type:"text"},{tags:"1,2,3",title:"Japan",type:"image"},{tags:"2,3",title:"Japan",type:"image"}]
const map = Object.fromEntries(array1.map(({ id, title }) => [id, title]));
const output = array2.map(({ tags, ...rest }) => {
const newTags = tags.replace(/\d+(?=,|$)/g, n => map[n])
return { tags: newTags, ...rest }
})
console.log(output)

Here's a solution
I'm using .map, .reduce and .replace to join array1 and array2 together.
const array1 = [
{
id: "1",
title: "Writing"
},
{
id: "2",
title: "Singing"
},
{
id: "3",
title: "Dance"
}
]
const array2 = [
{
tags: "1",
title: "USA",
type: "text"
},
{
tags: "1,2,3",
title: "Japan",
type: "image"
},
{
tags: "2,3",
title: "Japan",
type: "image"
}
]
const array3 =
array2.map(item => ({
...item,
tags: array1.reduce((tags, {id, title}) => tags.replace(id, title), item.tags),
}))
console.log(array3)

You can use filter, map and join method, split tags and filter tags in array1 first.
var newtags= (array2).map(obj=>{
let tags = obj.tags.split(",");
let titles = array1.filter(c=>tags.includes(c.id)).map(c=>c.title);
obj.tags = titles.join();
return obj;
});
array1 = [{id:"1",title:"Writing"},{id:"2",title:"Singing"},{id:"3",title:"Dance"}];
array2 = [{tags: "1",title: "USA",type: "text"},
{tags: "1,2,3",title: "Japan",type: "image"},
{tags: "2,3",title: "Japan",type: "image"}];
var newtags= (array2).map(obj=>{
let tags = obj.tags.split(",");
let titles = array1.filter(c=>tags.includes(c.id)).map(c=>c.title);
obj.tags = titles.join();
return obj;
});
console.log(newtags);

You can try following
Use Array.reduce to convert array1 into an object with id as key and title as value (Step 1)
Iterate over array2 using Array.forEach to update its tags property
To update tags property first split it by , to convert into an array
Map each value in array to its corresponding value in Object created in step 1
Join back the array with , and assign back to tags
let array1 = [{id:"1",title:"Writing"},{id:"2",title:"Singing"},{id:"3",title:"Dance"}];
let array2 = [{tags: "1",title: "USA",type: "text"},{tags: "1,2,3",title: "Japan",type: "image"},{tags: "2,3",title: "Japan",type: "image"}];
let obj = array1.reduce((a,c) => Object.assign(a, {[c.id] : c.title}), {});
array2.forEach(o => o.tags = o.tags.split(",").map(v => obj[v]).join(","));
console.log(array2);

To achieve expected result, use below option of looping array1 and replacing array2 tags with title
Loop Array1 using forEach
Replace array2 tags with each array1 title using array id
array1 = [{id:"1",title:"Writing"},{id:"2",title:"Singing"},{id:"3",title:"Dance"}];
array2 = [{tags: "1",title: "USA",type: "text"},
{tags: "1,2,3",title: "Japan",type: "image"},
{tags: "2,3",title: "Japan",type: "image"}];
array1.forEach(v =>{
const re = new RegExp(v.id, "g");
array2 = JSON.parse(JSON.stringify(array2).replace(re, v.title))
})
console.log(array2);

I would consider breaking this down into several reusable functions. Of course it might be premature abstraction, but I've seen variants of this questions like often enough here that it makes sense to me to look toward the fundamentals.
We want to be able to look up the values in a list stored as an array with what might be arbitrary field names. So we use a function makeDictionary that takes both the field names and the array and returns an object that maps them, such as {'1': 'Writing', '2': 'Singing',...}`.
Then we can use fillField supplying a dictionary, a field name, and an object, and replace that field with the result of looking up the tags in the dictionary. This is a little more specific to the problem, mostly because the comma-separated string format for your tags is a little more cumbersome than it might be if it were an array.
With these, useTags is simple to write, and it is the first function here focused directly on your needs. It combines the above, supplying the field names id and title for the dictionary and tags for your main objects.
This is what it looks like combined:
const makeDictionary = (keyName, valName) => (arr) =>
arr .reduce
( (a, {[keyName]: k, [valName]: v}) => ({...a, [k]: v})
, {}
)
const fillField = (field, dict) => ({[field]: f, ...rest}) => ({
...rest,
[field]: f .split (/,\s*/) .map (t => dict[t]) .join (', ')
})
const useTags = (tags, dict = makeDictionary ('id', 'title') (tags) ) =>
(objs) => objs .map ( fillField ('tags', dict) )
const tags = [{id: "1", title: "Writing"}, {id: "2", title: "Singing"}, {id: "3", title: "Dance"}];
const updateTags = useTags (tags)
const items = [{tags: "1", title: "USA", type: "text"}, {tags: "1, 2, 3", title: "Japan", type: "image"}, {tags: "2, 3", title: "Japan", type: "image"}];
console .log (
updateTags (items)
)
Note that I took a little liberty with the tags: "2,3" and tags: "Singing,Dance" formats, adding a little white space. It's trivial to take this out. But even better, if possible, would be to change this to use arrays for your tags.

You could take a real Map and map the values to the new objects.
var array1 = [{ id: "1", title: "Writing" }, { id: "2", title: "Singing" }, { id: "3", title: "Dance" }],
array2 = [{ tags: "1", title: "USA", type: "text" }, { tags: "1,2,3", title: "Japan", type: "image" }, { tags: "2,3", title: "Japan", type: "image" }],
tags = array1.reduce((m, { id, title }) => m.set(id, title), new Map),
result = array2.map(o => ({ ...o, tags: o.tags.split(',').map(Map.prototype.get, tags).join() }));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

how to get id based on value of objects and set into another object - javascript

There are two array of objects and i want to filter two values by iterating differently to get two different id.
Here is the example
1st array : list_of_products: [ { text: "Shoes", value: 1},{text:"Clothing", value: 2},{text:"Foods", value: 3}]
2nd Array: list_of_names: [{ text: "jim" , value: 1},{text:"Sim", value: 2},{text:"Tim",value:3}]
Now, i want to get the ids by filtering out two arrays based on names like this
product_name: "Clothing", person_name:"Tim"
Then i want to store the ids like this
const newIds = { product_id: 2,name_id: 3}
This i have tried:
const newProduct_name = list_of_products.find(name => name.text === product_name);
const newName = list_of_names.find(name => name.text === person_name);
storing it into new object like this
const values = {product_id: newProduct_name.value ,name_id: newName.value}
How to do this by minimal use of variables and faster execution?
Creating Maps or objects using the lookup values as keys lets you iterate each of your source arrays once and then have o(1) searches rather than using find() to iterate each array many times
const products= [ { text: "Shoes", value: 1},{text:"Clothing", value: 2},{text:"Foods", value: 3}],
names= [{ text: "jim" , value: 1},{text:"Sim", value: 2},{text:"Tim",value:3}];
const createMap = (arr) => new Map(arr.map(o => [o.text, o.value])),
prodMap = createMap(products),
namesMap = createMap(names);
const data = [{
product_name: "Clothing",
person_name: "Tim"
}];
const res = data.map(o => {
return {
product_id: prodMap.get(o.product_name),
name_id: namesMap.get(o.person_name)
};
})
console.log(res)

Javascript or Ramda Transform JSON By Attributes

I am using Ramda library in my project.
is it possible to transform following JSON array
from
[
{
"id": 1,
"name": "test",
},
{
"id": 2,
"name": "test2"
}
];
To
[
{
"id": 1,
"id": 2,
},
{
"name": "test",
"name": "test2"
}
];
pleas help
As OriDrori pointed out, your requested output is not valid JS. I'm going to make a slightly different guess, though, as to a useful variant of it that is valid, namely that we want an output like this:
{
id: [1, 2],
name: ['test1', 'test2']
}
Here's one simple way to achieve that in vanilla JS:
const extract = (data) => {
const keys = [... new Set (data .flatMap (Object .keys))]
return Object .fromEntries (
keys.map (k => [k, data .map (o => o [k])])
)
}
const data = [{id: 1, name: "test"}, {id: 2, name: "test2"}]
console .log (
extract (data)
)
We can definitely clean that up with Ramda functions. Another version might look like this:
const extract = (data) => fromPairs (
map (k => [k, map (o => o [k], data)]) (uniq (chain (keys) (data)))
)
const data = [{id: 1, name: "test"}, {id: 2, name: "test2"}]
console .log (extract (data))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js"></script>
<script> const {fromPairs, map, uniq, chain, keys} = R </script>
While we could go completely point-free, I find this version much less readable:
const extract = compose (
fromPairs,
lift (map) (
unary (compose (ap (pair), flip (pluck))),
compose (uniq, chain (keys))
)
)
const data = [
{id: 1, name: "test"},
{id: 2, name: "test2"}
]
console .log (extract (data))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js"></script>
<script>
const {compose, fromPairs, lift, map, unary, ap, pair, flip, pluck, uniq, chain, keys} = R
</script>
Objects can't have multiple properties with the same key, so
{ "id": 1, "id": 2 } and { "name": "test", "name": "test2" } are invalid. I assume that you need an array of ids and an array of names:
[[1, 2, 3], ['test', 'test2', 'test3']]
If all objects are have the same order of keys - ie no { id: 1, name: 'test'} and { name: 'test2', id: 1 }, and you need all the values in an object, you can map the objects to their values, and then transpose:
const { pipe, map, values, transpose } = R;
const fn = pipe(
map(values),
transpose,
);
const arr = [{"id":1,"name":"test"},{"id":2,"name":"test2"},{"id":3,"name":"test3"}];
const result = fn(arr);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>
If some objects have a different keys insertion order, you want to change the order of the resulting arrays, or if you need some of the keys, you can get the values with R.props, and then transpose:
const { pipe, map, props, transpose } = R;
const fn = pipe(
map(props(['name', 'id'])), // example - name would be the 1st sub-array
transpose,
);
const arr = [{"id":1,"name":"test"},{"id":2,"name":"test2"},{"id":3,"name":"test3"}];
const result = fn(arr);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>
If you want the structure suggested by Scott Sauyet's:
{
id: [1, 2],
name: ['test1', 'test2']
}
I would map and flatten the objects to an array of pairs with R.chain and R.toPairs, group them by the 1st item in each pair (the original key), and then map each groups item to the last item in each pair (the original value).
const { pipe, chain, toPairs, groupBy, head, map, last } = R
const fn = pipe(
chain(toPairs),
groupBy(head),
map(map(last)), // map(pipe(map(last), uniq)) if you want only unique items
)
const arr = [{"id":1,"name":"test"},{"id":2,"name":"test2"},{"id":3,"name":"test3"}];
console.log(fn(arr))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js"></script>

How to compare two different arrays which has different property names and remove unmatched ones in javascript?

I havve two different arrays with different property names like below
arrayA = [
{ id: 20, name: 'Jason' },
{ id: 15, name: 'Harry' },
{ id: 5, name: 'Clara' },
{ id: 9, name: 'Melonie' }
]
arrayB = [
{ courseID: 12, studentID: 20 },
{ courseID: 12, studentID: 15 }
]
I want to compare these two different arrays and remove unmatched ids from arrayA. For comparison, id field of arrayA and studentID field of arrayB matters. if these fileds aren't equal to each other, they should be removed from arrayA.
Expected is below
arrayA = [{id: 20, name: 'Jason' }, { id: 15, name: 'Harry' }]
Here is what I tried below but didn't work. Gave me empty array.
filteredElements = this.arrayA.map(e => e.id).filter(
val => this.arrayB.indexOf(val.studentID) !== -1
);
You can do that in following steps:
Use map() on arrayB and create array of courseID.
Then create a Set() from that Array
Then use filter() arrayA and check whether id of object exists in above created Set or not using Set.prototype.has()
const arrayA = [{id:20,name:'Jason'},{id:15,name:'Harry'},{id:5,name:'Clara'},{id:9,name:'Melonie'}]
const arrayB =[{courseID:12,studentID:20},{courseID:12,studentID:15}];
const ids = new Set(arrayB.map(x => x.studentID));
const res = arrayA.filter(x => ids.has(x.id));
console.log(res);
let arrayA = [{id: 20,name: 'Jason'},{id: 15,name: 'Harry'},{id: 5,name: 'Clara'},{id: 9,name: 'Melonie'}]
let arrayB = [{courseID: 12,studentID: 20},{courseID: 12,studentID: 15}];
let filtered=arrayA.filter(obj =>{ if(arrayB.find(course => course.studentID == obj.id))return true;return false;
});
console.log(filtered);
Try this:
var studentIds = arrayB.map(course => course.studentID);
var result = arrayA.filter(student => studentIds.includes(student.id));
The variable result contains your result.
Create a dictionary from courseMembers, keyed on studentID, to enable O(1) lookup.
Filter students according to the dictionary.
const students = [{id:20,name:'Jason'},{id:15,name:'Harry'},{id:5,name:'Clara'},{id:9,name:'Melonie'}]
const courseMembers = [{courseID:12,studentID:20},{courseID:12,studentID:15}]
function withCourses(students, courseMembers) {
const map = courseMembers.reduce((acc, {studentID}) =>
(acc[studentID] = true, acc), {})
return students.filter(({id}) => map[id])
}
const result = withCourses(students, courseMembers)
console.log(result) // [{ id:20, name:"Jason" },{ id:15, name:"Harry" }]

JS compare two arrays with objects and remove duplicated by property name ES6 way

Wanted to compare two arrays with objects and remove duplicate by its property name, I have these two:
arr1 = [{
item:"apple",
description: "lorem"
},{
item:"peach",
description: "impsum"
}]
arr2 = [{
item:"apple", description: "dolor"
},{
item:"grape", description: "enum"
}]
and I wanted this result:
arr3 = [{
item:"peach", description: "impsum"
},{
item:"grape", description: "enum"
}]
I've tried this es6 approach but not working arr3 = arr1.filter(val => !arr2.includes(val));
Array.includes won't work because in javascript {} !== {}. You'll need another way like Array.every to check that every object in the other array doesn't have the same value of the property item as the current object. Also, you need to do both arr1.filter(...) and arr2.filter(...) and concat the results:
arr3 = [].concat(
arr1.filter(obj1 => arr2.every(obj2 => obj1.item !== obj2.item)),
arr2.filter(obj2 => arr1.every(obj1 => obj2.item !== obj1.item))
);
Example:
let arr1 = [{
item:"apple",
description: "lorem"
},{
item:"peach",
description: "impsum"
}];
let arr2 = [{
item:"apple", description: "dolor"
},{
item:"grape", description: "enum"
}];
let arr3 = [].concat(
arr1.filter(obj1 => arr2.every(obj2 => obj1.item !== obj2.item)),
arr2.filter(obj2 => arr1.every(obj1 => obj2.item !== obj1.item))
);
console.log(arr3);
See Set, Array.prototype.filter() and Spread Syntax for more info.
// Join Without Dupes.
const joinWithoutDupes = (A, B) => {
const a = new Set(A.map(x => x.item))
const b = new Set(B.map(x => x.item))
return [...A.filter(x => !b.has(x.item)), ...B.filter(x => !a.has(x.item))]
}
// Proof.
const output = joinWithoutDupes([{item:"apple",description: "lorem"},{item:"peach",description: "impsum"}], [{item:"apple", description: "dolor"},{item:"grape", description: "enum"}])
console.log(output)
a simple and faster sample:
arr1 = [{
item:"apple",
description: "lorem"
},{
item:"peach",
description: "impsum"
}]
arr2 = [{
item:"apple", description: "dolor"
},{
item:"grape", description: "enum"
}]
result = (counters = {}, arr1.concat(arr2).map(cur => (counters[cur.item] ? counters[cur.item]++ : (counters[cur.item] = 1), cur)).filter(cur => counters[cur.item] === 1))
console.log(result)

Nested iteration over collection

I am trying to assemble a string using output from two collections. To do that, I iterate over one of them, using _forEach function, and use it's output as an input for another iterator. But I can't make it work.
Code:
const data1 = [{
label: 'Id',
data: 'id'
},
{
label: 'First name',
data: 'first_name'
},
{
label: 'Last name',
data: 'last_name'
},
{
label: 'IP Address',
data: 'ip_address'
},
];
const data2 = [{
"id": 1,
"first_name": "Robinet",
"last_name": "Golsby",
"ip_address": "201.83.127.236"
}, {
"id": 2,
"first_name": "Kirby",
"last_name": "Feaver",
"ip_address": "143.188.49.149"
}]
let keys = '';
const getKeys = _.forEach(data1, value => keys += '' +value.data);
let stringValue = '';
const getStringValue = _.forEach(tableData, value => stringValue += ' ' + value.first_name);
So I can get a list of keys from the first object, and I can get the list of values from the second, but only if the key is hardcoded. What I want to do is to iterate over each of the entries in data2 in the 'outer' iterator, while providing keys to get the values using iteration over data1. How do I do that?
Edit: the end result would look like:
1 Robinet Golsby 201.83.127.236
seems like:
const result = _.chain(data1)
.map('data') // get keys from data1
.thru(keys => _.map(data2, item => _.at(item, keys))) // iterate data2 and get values by keys
.map(values => _.join(values, ' ')) // values array to string
.value();
result:
["1 Robinet Golsby 201.83.127.236", "2 Kirby Feaver 143.188.49.149"]
I'm not sure if this is exactly what you want, but I think that you can achieve your goal using nesting Array#map calls:
const data1 = [{"label":"Id","data":"id"},{"label":"First name","data":"first_name"},{"label":"Last name","data":"last_name"},{"label":"IP Address","data":"ip_address"}];
const data2 = [{"id":1,"first_name":"Robinet","last_name":"Golsby","ip_address":"201.83.127.236"},{"id":2,"first_name":"Kirby","last_name":"Feaver","ip_address":"143.188.49.149"}];
const result = data2.map((obj) => data1.map(({ label, data }) => ({
label,
data: obj[data]
})));
console.log(result);

Categories

Resources