Related
i want to add a field type to each object in an array and push the result to another array and push that to another array.
below is how the array of object looks,
const arrObj1 = [
{
id: '1',
name: 'n1',
},
{
id: '2',
name: 'n2',
}
]
const arrObj2 = [
{
id: '3',
name: 'n3',
},
{
id: '4',
name: 'n4',
}
]
what i am trying to do?
i want to add a type field with value 'type1' to arrObj1 and type field with value 'type2' to arrObj2
so the output should be like below,
const arrObj1 = [
{
id: '1',
name: 'n1',
type: 'type1',
},
{
id: '2',
name: 'n2',
type: 'type1',
}
]
const arrObj2 = [
{
id: '3',
name: 'n3',
type: 'type2',
},
{
id: '4',
name: 'n4',
type: 'type2',
}
]
then i want to combine these two arrays arrObj1 and arrObj2 into one array like below
const combinedArrObj = [
{
id: '1',
name: 'n1',
type: 'type1',
},
{
id: '2',
name: 'n2',
type: 'type1',
},
{
id: '3',
name: 'n3',
type: 'type2',
},
{
id: '4',
name: 'n4',
type: 'type2',
}
]
what i have tried?
const arrObj1Res = arrObj1.map((obj: any) => {
return {
...arrObj1,
type: 'type1',
}
});
const arrObj2Res = arrObj2.map((obj: any) => {
return {
...arrObj2,
type: 'type2',
}
});
const combinedArrObj = [
...arrObj1Res,
...arrObj2Res,
];
this works. but how can i refactor to something simple rather than adding field type for each obj in array and then combine
could someone help me with this. thanks.
you can use this
let result=arrObj1.concat(arrObj2)
function contains(a, obj) {
for (var i = 0; i < a.length; i++) {
if (a[i] === obj) {
return true;
}
}
return false;
}
result.filter(element => {
if (contains(arrObj1,element) ){
element.type='type1'
return element
}else {
element.type='type2'
return element
}
});
In pure JS, just a simple for loop can do the part where you add a field named type.
for(var i = 0; i < arrObj1.length; i++){
arrObj1[i].type = "type1";
}
for(var i = 0; i < arrObj2.length; i++){
arrObj2[i].type = "type2";
}
and to combine the arrays together just use concat.
const combinedArrObj = arrObj1.concat(arrObj2);
const allArrayObject = arrObj1.concat(arrObj2);
const finalResultArray = allArrayObject.reduce((finalResultArray, eachArrayObj, index) =>{
const isTypeOne = arrObj1.length - 1 >= index
const relevantTypeString = isTypeOne ? "type1" : "type2"
eachArrayObj.type = relevantTypeString
finalResultArray.push(eachArrayObj)
return finalResultArray
}, [])
I am trying to filter through an object with multiple key/value pairs by a specific key. It appears that the code I've written is searching the entire object regardless of the key...
If key name contains the search term, return the search term.
Array of Objects:
export const someArrayOfObjects = [
{ id: '1', name: 'Something' },
{ id: '2', name: 'Another' },
{ id: '3', name: 'Lets do one more' },
]
Search:
const searchResults = someArrayOfObjects.filter((o) =>
Object.keys(o).some((k) => o[k].toString().toLowerCase().includes(searchTerm.toLowerCase()))
);
So if I search "Something", I only want it to loop through name to search for that term...
You don't need the Object.keys loop.
const someArrayOfObjects = [
{ id: '1', name: 'Something' },
{ id: '2', name: 'Another' },
{ id: '3', name: 'Lets do one more' },
];
let key = 'name';
let searchTerm = 'th';
const res = someArrayOfObjects.filter(o =>
o[key].toLowerCase().includes(searchTerm.toLowerCase()));
console.log(res);
similar to iota's, you don't need to create the extra array with Object.keys.
just loop/check every item inside the original array with the 'name' key.
you can also try to make it more reusable like below.
const someArrayOfObjects = [
{ id: '1', name: 'Something' },
{ id: '2', name: 'Another' },
{ id: '3', name: 'Lets do one more' },
];
const search = function (anyArray, searchTerm) {
return anyArray.filter((obj) => {
if (obj.name === searchTerm) {
return obj.name;
}
return false;
});
};
const case1 = search(someArrayOfObjects, 'Something');
console.log(case1);
I have an array of objects and array of strings
cities = [ { id: '1', name: 'Paris'}, { id: '2', name: 'Rome'}, { id: '3', name: 'London'}, { id: '4', name: 'Barcelona'}]
userChoice = ['2','4']
I need to iterate over cities with userChoice and find name of cities by id.
I guess it's going to be a nested loop, but I am strugling with it.
cities.filter(city=> userChoice.forEach(choice => choice == city.id))
You can use filter() and includes() to filter cities array by checking if a city's id is present in userChoice array.
To get just the names, you can use map() to transform the result.
let cities = [ { id: '1', name: 'Paris'}, { id: '2', name: 'Rome'}, { id: '3', name: 'London'}, { id: '4', name: 'Barcelona'}];
let userChoice = ['2','4'];
let filteredCities = cities.filter(city => userChoice.includes(city.id));
let names = filteredCities.map(city => city.name);
console.log(names);
You could use a Map object to look up ID based on city.
let cityMap = new Map(cities.map(c => [c.name, c.id]));
console.log(cityMap.get("Rome")); // --> "2"
Just use a simple map, you map the array element to the city from the other array. You might want to put a null check in if you can have values that might not be in the array but for simplicity I left it out.
const cities = [ { id: '1', name: 'Paris'}, { id: '2', name: 'Rome'}, { id: '3', name: 'London'}, { id: '4', name: 'Barcelona'}];
const userChoice = ['2','4'];
const userCities = userChoice.map(val => cities.find(c => c.id === val).name);
console.log(userCities)
With the following data structure...
const branches = [
{ id: '1', brand: { id: 'A' }},
{ id: '2', brand: { id: 'B' }},
{ id: '3', brand: { id: 'A' }}
]
I want to pick unique brands... that's easy enough.
const pickBrands = RM.pipe(
RM.map(RM.prop('brand')),
RM.uniqBy(RM.prop('id'))
)
But ultimately, I need to transform a whole thing like this...
const brands = [
{ id: 'A', branches: ['1', '3'] },
{ id: 'B', branches: ['2'] },
]
I am kinda confused how could I approach that considering that after the first map, I am losing information about a branch.
Final solution:
https://runkit.com/fredyc/5d2e1bf1df8aec001aff7f64
This might help too:
const group = R.pipe(
R.groupBy(R.path(['brand', 'id'])),
R.values,
R.map(
R.applySpec({
id: R.path([0, 'brand', 'id']),
branches: R.pluck('id'),
}),
),
);
const branches = [
{ id: '1', brand: { id: 'A' }},
{ id: '2', brand: { id: 'B' }},
{ id: '3', brand: { id: 'A' }}
];
console.log('group', group(branches));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
You can use R.groupBy with R.path to group by brand.id, and then use R.toPairs and R.map with R.zipObject to generate the new object from the groups.
Example (annotated by #ScottSauyet):
const { pipe, groupBy, path, map, pluck, toPairs, zipObj } = R
const fn = pipe(
groupBy(path(['brand', 'id'])), //=> {"A": [{brand: {id: "A"}, id: "1"}, {brand: {id: "A"}, id: "3"}], B: [{brand: {id: "B"}, id: "2"}]}
map(pluck('id')), //=> {A: ["1", "3"], B: ["2"]}
toPairs, //=> [["A", ["1", "3"]], ["B", ["2"]]]
map(zipObj(['id', 'brand']) ) //=> [{id: "A", brand: ["1", "3"]}, {id: "B", brand: ["2"]}]
)
const branches = [
{ id: '1', brand: { id: 'A' } },
{ id: '2', brand: { id: 'B' } },
{ id: '3', brand: { id: 'A' } }
]
const result = fn(branches)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
Note: My original solution used R.applySpec({ id: head, branches: last }), but it seems that I'm the only one to find it more readable.
You can use plain old JS to achieve your outcome, use reduce with findIndex to check if the id already exists, if it does, push the id to the existing object, otherwise, push the new object:
const branches = [
{ id: '1', brand: { id: 'A' }},
{ id: '2', brand: { id: 'B' }},
{ id: '3', brand: { id: 'A' }}
]
console.log(branches.reduce((a, {id, brand}) => {
const i = a.findIndex(o => o.id === brand.id)
i + 1 ? a[i].branches.id.push(id) : a.push({id: brand.id, branches: { id: [id] }})
return a
}, []))
You could take a Map for collecting brands.
const
branches = [{ id: '1', brand: { id: 'A' } }, { id: '2', brand: { id: 'B' } }, { id: '3', brand: { id: 'A' } }],
brands = Array.from(
branches.reduce((m, { id: branche, brand: { id } }) =>
m.set(id, [...(m.get(id) || []), branche]), new Map),
([id, branches]) => ({ id, branches: { id: branches }})
);
console.log(brands);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Here's a solution using values and reduceBy.
First let's define an empty template for brands:
const brandTmpl =
{ id: null,
branches: [] };
Then let's define a function that returns the brand id for a given branch:
const brandId = path(['brand', 'id']);
brandId({ id: '1', brand: { id: 'A' }});
//=> 'A'
Then given a brand and a branch, let's define a function that "adds" a branch to a brand:
const brand = (brd, bch) => (
{ id: brandId(bch),
branches: append(bch.id, brd.branches) });
brand(brandTmpl, { id: '1', brand: { id: 'A' }});
//=> {id: 'A', branches: ['1']}
Now let's use all of that to merge branches by brand:
const brands = reduceBy(brand, brandTmpl, brandId);
brands([
{ id: '1', brand: { id: 'A' }},
{ id: '2', brand: { id: 'B' }},
{ id: '3', brand: { id: 'A' }}]);
//=> { A: { id: "A", branches: ["1", "3"]},
//=> B: { id: "B", branches: ["2"]} }
Finally we can simply extract the values:
const branches = [
{ id: '1', brand: { id: 'A' }},
{ id: '2', brand: { id: 'B' }},
{ id: '3', brand: { id: 'A' }} ];
const brandId = path(['brand', 'id']);
const brandTmpl =
{ id: null,
branches: [] };
const brand = (brd, bch) => (
{ id: brandId(bch),
branches: append(bch.id, brd.branches) });
const brands = reduceBy(brand, brandTmpl, brandId);
const pickBrands = compose(values, brands);
console.log(
pickBrands(branches)
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
<script>const {path, append, reduceBy, compose, values} = R;</script>
try this:
const branches = [
{ id: '1', brand: { id: 'A' }},
{ id: '2', brand: { id: 'B' }},
{ id: '3', brand: { id: 'A' }}
]
const groupBy = (branches) => branches.reduce((acc, ele)=>( (acc[ele.brand.id] = acc[ele.brand.id] || []).push(ele), acc),{})
const reformat = ([k, v]) =>({id: k, branches: {id:v.map(({id})=>id)}})
const result = Object.entries(groupBy(branches)).map(ele => reformat(ele))
console.log(result);
I have two arrays of objects. Each collection object contains similar properties. I'm trying to zip together the two collections based on a specific property. It's possible, however, that a particular object in either array may not necessarily have a object with a matching property value in the other array. In these cases I'd like to have null values. Here's an example of what I'd like to do:
var arr1 = [
{ id: '1', text: 'arr1 - one' },
{ id: '2', text: 'arr1 - two' },
{ id: '3', text: 'arr1 - three' }
];
var arr2 = [
{ id: '1', text: 'arr2 - one' },
{ id: '2', text: 'arr2 - two' },
{ id: '4', text: 'arr2 - four' }
];
result:
{
'1': [
{ id: '1', text: 'arr1 - one' },
{ id: '1', text: 'arr2 - one' }
]
'2': [
{ id: '2', text: 'arr1 - two' },
{ id: '2', text: 'arr2 - two' }
],
'3': [
{ id: '3', text: 'arr1 - three' },
null
],
'4': [
null,
{ id: '4', text: 'arr2 - four' }
]
I do already have a lodash 4 dependency in the project, so answers using that library are welcome.
_.chain(arr1)
.concat(arr2)
.map('id')
.uniq() //get all possible ids without dublicates
.reduce(function (result, id) {
result[id] = _.map([arr1, arr2], function (arr) { //find object in each array by id
return _.find(arr, {id: id}) || null; //if not found set null
});
return result;
}, {})
.value();
function zip(a, b, propName) {
const result = new Map();
a.forEach(i=> result.set(i[propName], [i, null]));
b.forEach(i=> {
let item = result.get(i[propName]);
item ? (item[1] = i) : (result.set(i[propName], [null, i]));
});
return result;
}
var arr1 = [
{ id: '1', text: 'arr1 - one' },
{ id: '2', text: 'arr1 - two' },
{ id: '3', text: 'arr1 - three' }
];
var arr2 = [
{ id: '1', text: 'arr2 - one' },
{ id: '2', text: 'arr2 - two' },
{ id: '4', text: 'arr2 - four' }
];
console.log(JSON.stringify([...zip(arr1, arr2, 'id')], null, ' '));
According to the requirements listed, below should work (using Ramda, I believe the functions used should have according one in lodash/fp)
var arr1 = [
{ id: '3', text: 'arr1 - one' },
{ id: '2', text: 'arr1 - two' },
{ id: '1', text: 'arr1 - three' }
];
var arr2 = [
{ id: '4', text: 'arr2 - one' },
{ id: '2', text: 'arr2 - two' },
{ id: '1', text: 'arr2 - four' }
];
var idList = R.pipe(
R.concat,
R.map(R.prop('id')),
R.uniq,
R.sortBy(R.identity)
)(arr1, arr2);
var findById = (id) => R.find(R.propEq('id', id));
return R.map(
(id) => [
findById(id)(arr1),
findById(id)(arr2)
]
)(idList);
Here's the link. It's returning undefined instead of null, but you can map over it to change it if it matters.
However, depending on what the result would be used, if null value is not required at all, there is simpler version with groupWith
return R.pipe(
R.concat,
R.sortBy(R.prop('id')),
R.groupWith(R.eqProps('id'))
)(arr1, arr2);
link.
The thing that makes this a bit difficult is the need for null values in each grouping, which match the order in which they were grouped. For example, if you did not need the nulls, this problem would be as simple as:
_.groupBy(arr1.concat(arr2), 'id')
However, to group and maintain nulls, you need to add a bit of redundancy that groupBy does not come pre-baked with. You can write your own group function as such:
function group(...arrs) { // extensible to any number of arrays
// construct an object with empty arrays for all available ids
let rslt = _.chain(arrs)
.flatten()
.map(el => el.id)
.uniq()
.reduce((memo, el) => {
memo[el] = []
return memo
}, {})
.value()
// as we iterate, first set resulting object's bucket value to null
// Replace this value if it exists while iterating
_.each(arrs, (arr, i) => {
_.each(rslt, v => {
v.push(null)
})
_.each(arr, el => {
rslt[el.id][i] = el
})
})
return rslt
}
var arr1 = [{
id: '3',
text: 'arr1 - one'
}, {
id: '2',
text: 'arr1 - two'
}, {
id: '1',
text: 'arr1 - three'
}];
var arr2 = [{
id: '4',
text: 'arr2 - one'
}, {
id: '2',
text: 'arr2 - two'
}, {
id: '1',
text: 'arr2 - four'
}];
console.log(group(arr1, arr2))
<script src="https://cdn.jsdelivr.net/lodash/4.17.2/lodash.min.js"></script>
^ Run the snippet to see a log of the result.
You can do this with _.groupBy() and _.mapValues():
const zipByKey = (arr1, arr2, zipKey) => {
// group arr2 by the zipKey
const group2 = _.groupBy(arr2, zipKey);
return _(arr1)
// group arr1 by the zipKey
.groupBy(zipKey)
// merge group1 with group2, if object is not in group1 substitute with null
.mergeWith(group2, (objValue, srcValue) => (objValue || [null]).concat(srcValue))
// map the groups, if object is not in group2 substitute with null
.mapValues((group, zipKey) => group2[zipKey] ? group : group.concat(null))
.value();
}
const arr1 = [{"id":"1","text":"arr1 - one"},{"id":"2","text":"arr1 - two"},{"id":"3","text":"arr1 - three"}], arr2 = [{"id":"1","text":"arr2 - one"},{"id":"2","text":"arr2 - two"},{"id":"4","text":"arr2 - four"}];
const result = zipByKey(arr1, arr2, 'id');
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>