Map being skipped on array of objects - javascript

I can't figure out why my map is not resolving. It's somehow skipping my map even though countriesAtoH shows me that it does have an array of objects in it but when I try to map over it, it's like it doesn't map it, because I can't put breakpoints inside map and map ultimately is not invoked. Meaning I get a length of 0 on options
const countries = {
Afghanistan: {
countryId: 0,
name: "Afghanistan"
},
Albania: {
countryId: 1,
name: "USA"
},
Algeria: {
countryId: 99,
name: "Canada"
}
}
export const countryOptions = () => {
let countriesAtoH = [];
Object.keys(countries).forEach((c) => {
if (countries[c].countryId <= 97) {
countriesAtoH[c] = countries[c];
}
});
const options = countriesAtoH.map(country => {
const c = {
text: {
type: "plain_text",
text: country.name,
},
value: country.countryId
}
return c;
});
return options;
}

In this line:
countriesAtoH[c] = countries[c];
c is country name as string, not number as array index, so the country will not be push to the array. So the array is still empty as Array(0) in your log.
You may want to do array push here:
countriesAtoH.push(countries[c]);

You have problems on countriesAtoH[c] = countries[c] part.
The type of countriesAtoH is array so the index should be the number and you are assigning c value (string) value as the index on countriesAtoH array.
Therefore, it is not working. It's better to set countriesAtoH = {} as object and use Object.values(countriesAtoH) on getting options variable.
const countries = {
Afghanistan: {
countryId: 0,
name: "Afghanistan"
},
Albania: {
countryId: 1,
name: "USA"
},
Algeria: {
countryId: 99,
name: "Canada"
}
}
const countryOptions = () => {
let countriesAtoH = {};
Object.keys(countries).forEach((c) => {
if (countries[c].countryId <= 97) {
countriesAtoH[c] = countries[c];
}
});
const options = Object.values(countriesAtoH).map((country) => {
const c = {
text: {
type: "plain_text",
text: country.name,
},
value: country.countryId
}
return c;
});
return options;
}
console.log(countryOptions());
Simply, you can use Array.prototype.filter and Array.prototype.map to get the options.
const countries = {
Afghanistan: {
countryId: 0,
name: "Afghanistan"
},
Albania: {
countryId: 1,
name: "USA"
},
Algeria: {
countryId: 99,
name: "Canada"
}
}
const countryOptions = () => {
const options = Object.values(countries).filter(({ countryId }) => countryId <= 97).map((item) => ({
text: {
type: "plain_text",
text: item.name
},
value: item.countryId
}));
return options;
}
console.log(countryOptions());

Related

How to convert array of objects into enum like key value pair in javascript?

I have an array
const a = [
{ name: "read-web-courses" },
{ name: "example" },
{ name: "t_gql" },
{ name: "ddddd" },
];
I am trying it to reduce it to the below given output , However I am stuck
Output
{0:"read-web-courses",1:"example",2:"t_gql",3:"ddddd"}
You could map the wanted property and assign the pairs to the object.
const
array = [{ name: "read-web-courses" }, { name: "example" }, { name: "t_gql" }, { name: "ddddd" }],
result = Object.assign({}, array.map(({ name }) => name));
console.log(result);
You can use Array.reduce like below.
const a = [
{ name: "read-web-courses" },
{ name: "example" },
{ name: "t_gql" },
{ name: "ddddd" },
];
const convert = arr => (
arr.reduce((total, value, index) => {
total[index] = value.name;
return total;
}, {})
)
console.log(convert(a));
This is accomplished using Array#reduce, where you can use the index from the reduce callback as the key of the new object:
const a = [ { name: "read-web-courses" }, { name: "example" }, { name: "t_gql" }, { name: "ddddd" }];
const res = a.reduce((r, o, i) => {
r[i] = o.name;
return r;
}, {});
console.log(res);
Also one more approach using Object#fromEntries and Array#map, where each object is converted to an array of key, value pairs:
const a = [ { name: "read-web-courses" }, { name: "example" }, { name: "t_gql" }, { name: "ddddd" }];
const res = Object.fromEntries(a.map((o, i) => [i, o.name]));
console.log(res)

Algorithm from folderstring to correct folderstructure in javascript

I have an array of data which is a string of folders:
var data = [{ name: "/X" }, { name: "/X/Y" }, { name: "/X2" }, { name: "/X2/Z" }, { name: "/X/k" }]
For a component to display this items I need them sorted nested like these:
var data = [{ name: "/X", sub: [{ name: "/Y" }, { name: "/k" }]}, { name: "/X2" }, sub: [{ name: "/Z" }] }]
These items are just examples, the item count is 1000+ and the nested items can be unlimited too.
Any ideas how to do that?
You could do this with forEach and reduce methods and use one object to keep track of level based on the current part of the name property value.
const data = [{ name: "/X" }, { name: "/X/Y" }, { name: "/X2" }, { name: "/X2/Z" }, {name: '/X/K/1'}, {name: '/X/K/2'}]
const result = []
const level = {result}
data.forEach(({ name, ...rest }) => {
name.split('/').filter(Boolean).reduce((r, k) => {
if (!r[k]) {
r[k] = { result: [] }
r.result.push({
name: `/${k}`,
sub: r[k].result
})
}
return r[k]
}, level)
})
console.log(result)
Using reduce() and Map()
var data = [{ name: "/X" }, { name: "/X/Y" }, { name: "/X2" }, { name: "/X2/Z" }, { name: "/X/k" }]
var res = data.reduce((a, i) => {
let s = i.name.match(/\/\w+/g) || []
if (a.has(s[0])) {
let path = a.get(s[0])
i.name = s[1]
path.sub = path.sub || []
path.sub.push(i)
} else {
a.set(i.name, i)
}
return a
}, new Map())
console.log([...res.values()])

How to filter the array using the content of another array?

The code looks as following:
inputArray = [
{ name: 'file1.jpg' },
{ name: 'file1.jpg' },
{ name: 'file2.jpg' },
{ name: 'file3.jpg' },
{ name: 'file4.jpg' }
]
filteringArray = ['file1', 'file2']
const outputArray = inputArray.filter( ? )
I need to filter the inputArrat so that the outputArray should contain only objects, which filenames ('name' property) are in filteringArray.
outputArray = [
{ name: 'file1.jpg' },
{ name: 'file2.jpg' }
]
I've worked so far with simpler filtering conditions, but I'm not sure how to solve this.
You can use .some() with .starsWith() to return true if the objects name starts with a file name present in your array like so:
const inputArray = [
{ name: 'file1.jpg' },
{ name: 'file2.jpg' },
{ name: 'file3.jpg' },
{ name: 'file4.jpg' }
];
const filteringArray = ['file1', 'file2'];
const outputArray = inputArray.filter(({name}) => filteringArray.some(file => name.startsWith(file)));
console.log(outputArray);
If you're looking for a solution which has a better time complexity (and has no duplicates), you could create a Map, which stores prefix file names as keys and the literal objects as values. Then, you can .map() your filteringArray using this map:
const inputArray = [
{ name: 'file1.jpg' },
{ name: 'file1.jpg' },
{ name: 'file2.jpg' },
{ name: 'file3.jpg' },
{ name: 'file4.jpg' }
]
const filteringArray = ['file1', 'file2'];
const lut = new Map(inputArray.map(({name}) => [name.split('.').shift(), {name}]));
const outputArray = filteringArray.map(f => lut.get(f));
console.log(outputArray);
You can use combination of filter and includes!
const inputArray = [
{ name: 'file1.jpg' },
{ name: 'file2.jpg' },
{ name: 'file3.jpg' },
{ name: 'file4.jpg' }
]
const filteringArray = ['file1', 'file2']
const outputArray = inputArray.filter((person) => filteringArray.includes(person.name.split(".")[0]))
console.log(outputArray);
You can use a simple function to do filter operation in the array using the filter logic array items as below.
var outputArray = [];
var inputArray = [
{ name: 'file1.jpg' },
{ name: 'file1.jpg' },
{ name: 'file2.jpg' },
{ name: 'file3.jpg' },
{ name: 'file4.jpg' }
];
var filteringArray = ['file1', 'file2'];
function filterItems(arr, query) {
arr.filter(function(el) {
query.forEach(function(item){
if(el.name.toLowerCase().indexOf(item.toLowerCase()) !== -1){
outputArray.push(el.name);
}
});
});
}
filterItems(inputArray, filteringArray);
console.log(remove_duplicates(outputArray));
function remove_duplicates(arr) {
var obj = {};
var ret_arr = [];
for (var i = 0; i < arr.length; i++) {
obj[arr[i]] = true;
}
for (var key in obj) {
ret_arr.push(key);
}
return ret_arr;
}
NOTE: Updated the code, Now input array is having duplicate values. And in output array, there is no duplicate entry as I removed duplicates using a function (Remove duplicate values from JS array)

How to merge Array of Objects based on the same value?

I have this array of Objects:
var array = [{
country: "Austria",
name: "2019-01-04T23:00:00.000Z",
value: "1"
},
{
country: "Austria",
name: "2019-01-11T23:00:00.000Z",
value: "3"
},
{
country: "Austria",
name: "2019-01-18T23:00:00.000Z",
value: "1"
}
]
I want manipulate this to achieve this result:
var array = [{
country: "Austria",
series: [{
name: "2019-01-04T23:00:00.000Z",
value: "1"
},
{
name: "2019-01-11T23:00:00.000Z",
value: "3"
},
{
name: "2019-01-18T23:00:00.000Z",
value: "1"
}
]
}]
I read many questions but none helped me.
You could loop thorugh the array. Use destructuring to get country and rest of the properties separately. Add each unique country to group object as key and push the rest object to the series array. Then use Object.values() to get the values as an array
const array=[{country:"Austria",name:"2019-01-04T23:00:00.000Z",value:"1"},{country:"Austria",name:"2019-01-11T23:00:00.000Z",value:"3"},{country:"Austria",name:"2019-01-18T23:00:00.000Z",value:"1"}];
const group = {};
array.forEach(({ country, ...rest }) => {
group[country] = group[country] || { country, series: [] };
group[country].series.push(rest)
})
console.log(Object.values(group))
This should do:
var map = {};
for(var entity of array) {
if(!map[entity.country]) {
map[entity.country] = {
country: entity.country,
series: [
{
name: entity.name,
value: entity.value
}
]
};
}
else {
map[entity.country].series.push({
name: entity.name,
value: entity.value
});
}
}
var mappedArray = Object.values(map);
Here is functional solution without for loops and mutable variables:
const result = array.reduce((carry, item) => {
if (!carry.includes(item.country)) {
carry.push(item.country);
}
return carry;
}, []).map(country => {
return {
country: country,
series: array.filter(item => item.country === country).map(item => {
return {
name: item.name,
value: item.value
};
})
};
You can do something like:
const result = array
.map(
c => ({
country: c.country,
series: array
.filter(d => d.country === c.country)
.map(
d => ({
name: d.name,
value: d.value
})
)
})
)

Get list of duplicate objects in an array of objects

I am trying to get duplicate objects within an array of objects. Let's say the object is like below.
values = [
{ id: 10, name: 'someName1' },
{ id: 10, name: 'someName2' },
{ id: 11, name: 'someName3' },
{ id: 12, name: 'someName4' }
];
Duplicate objects should return like below:
duplicate = [
{ id: 10, name: 'someName1' },
{ id: 10, name: 'someName2' }
];
You can use Array#reduce to make a counter lookup table based on the id key, then use Array#filter to remove any items that appeared only once in the lookup table. Time complexity is O(n).
const values = [{id: 10, name: 'someName1'}, {id: 10, name: 'someName2'}, {id: 11, name:'someName3'}, {id: 12, name: 'someName4'}];
const lookup = values.reduce((a, e) => {
a[e.id] = ++a[e.id] || 0;
return a;
}, {});
console.log(values.filter(e => lookup[e.id]));
Let's say you have:
arr = [
{ id:10, name: 'someName1' },
{ id:10, name: 'someName2' },
{ id:11, name: 'someName3' },
{ id:12, name: 'someName4' }
]
So, to get unique items:
unique = arr
.map(e => e['id'])
.map((e, i, final) => final.indexOf(e) === i && i)
.filter(obj=> arr[obj])
.map(e => arr[e]);
Then, result will be
unique = [
{ id:10, name: 'someName1' },
{ id:11, name: 'someName3' },
{ id:12, name: 'someName4' }
]
And, to get duplicate ids:
duplicateIds = arr
.map(e => e['id'])
.map((e, i, final) => final.indexOf(e) !== i && i)
.filter(obj=> arr[obj])
.map(e => arr[e]["id"])
List of IDs will be
duplicateIds = [10]
Thus, to get duplicates objects:
duplicate = arr.filter(obj=> dublicateIds.includes(obj.id));
Now you have it:
duplicate = [
{ id:10, name: 'someName1' },
{ id:10, name: 'someName2' }
]
Thanks https://reactgo.com/removeduplicateobjects/
You haven't clarified whether two objects with different ids, but the same "name" count as a duplicate. I will assume those do not count as a duplicate; in other words, only objects with the same id will count as duplicate.
let ids = {};
let dups = [];
values.forEach((val)=> {
if (ids[val.id]) {
// we have already found this same id
dups.push(val)
} else {
ids[val.id] = true;
}
})
return dups;
With lodash you can solve this with filter and countBy for complexity of O(n):
const data = [{ id: 10,name: 'someName1' }, { id: 10,name: 'someName2' }, { id: 11,name: 'someName3' }, { id: 12,name: 'someName4' } ]
const counts = _.countBy(data, 'id')
console.log(_.filter(data, x => counts[x.id] > 1))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
You could do the same with ES6 like so:
const data = [{ id: 10,name: 'someName1' }, { id: 10,name: 'someName2' }, { id: 11,name: 'someName3' }, { id: 12,name: 'someName4' } ]
const countBy = (d, id) => d.reduce((r,{id},i,a) => (r[id] = a.filter(x => x.id == id).length, r),{})
const counts = countBy(data, 'id')
console.log(data.filter(x => [x.id] > 1))
You can use an array to store unique elements and use filter on values to only return duplicates.
const unique = []
const duplicates = values.filter(o => {
if(unique.find(i => i.id === o.id && i.name === o.name)) {
return true
}
unique.push(o)
return false;
})
With lodash you can use _.groupBy() to group elements by their id. Than _.filter() out groups that have less than two members, and _.flatten() the results:
const values = [{id: 10, name: 'someName1'}, {id: 10, name: 'someName2'}, {id: 11, name:'someName3'}, {id: 12, name: 'someName4'}];
const result = _.flow([
arr => _.groupBy(arr, 'id'), // group elements by id
g => _.filter(g, o => o.length > 1), // remove groups that have less than two members
_.flatten // flatten the results to a single array
])(values);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
An alternative based in #ggorlen solution with new Map() as accumulator (for better performance) and without unary operator ++ (not advised by default in projects with ESLint).
const values = [{ id: 10, name: "someName1" }, { id: 10, name: "someName2" }, { id: 11, name: "someName3" }, { id: 12, name: "someName4" },];
const lookup = values.reduce((a, e) => {
a.set(e.id, (a.get(e.id) ?? 0) + 1);
return a;
}, new Map());
console.log(values.filter(e => lookup.get(e.id) > 1));
Try this
function checkDuplicateInObject(propertyName, inputArray) {
var seenDuplicate = false,
testObject = {};
inputArray.map(function(item) {
var itemPropertyName = item[propertyName];
if (itemPropertyName in testObject) {
testObject[itemPropertyName].duplicate = true;
item.duplicate = true;
seenDuplicate = true;
}
else {
testObject[itemPropertyName] = item;
delete item.duplicate;
}
});
return seenDuplicate;
}
referred from : http://www.competa.com/blog/lets-find-duplicate-property-values-in-an-array-of-objects-in-javascript/

Categories

Resources