Trying to get an object value in from a key in Javascript - javascript

I'm trying to get a country label (name) from a value (country code) in an object.
In Vue.js I'm trying to build a computed property to return the name of the country based on the country code from an API request.
In the template:
countryLabel () {
var countries = require('../../plugins/countries')
var countryCode = this.content.country
function getLabelByValue(countries, countryCode) {
return Object.keys(countries).find(label => countries[value] === countryCode)
}
}
From a list of countries:
module.exports = [
{ value: 'AF', label: 'Afghanistan' },
{ value: 'AX', label: 'Aland Islands' },
{ value: 'AL', label: 'Albania' },
{ value: 'DZ', label: 'Algeria' },
{ value: 'AS', label: 'American Samoa' },
{ value: 'AD', label: 'Andorra' },
{ value: 'AO', label: 'Angola' },
{ value: 'AI', label: 'Anguilla' },
{ value: 'AQ', label: 'Antarctica' },
{ value: 'AG', label: 'Antigua and Barbuda' },
...
]

You probably don't want to be calling Object.keys on an array.
Something like this is probably more what you want:
function getLabelByValue(countries, countryCode) {
const entry = countries.find(item => item.value === countryCode);
return entry ? entry.label : null;
}
The problem is that calling Object.keys on an array will return an array of numbers that have been converted to strings:
> console.log(Object.keys(['this', 'is', 'an', 'array']));
['0', '1', '2', '3']
Since your exports is already an array, you can call find() on it directly.

A better way to do this would be to use an object, which is always the fastest way to lookup anything in javascript because objects are dictionaries. So if you changed your export to look like:
{
AF: 'Afghanistan',
AX: 'Aland Islands',
etc...
}
then you'd be able to do instant lookups by doing countries[countryCode].

Based on rossipedia's answer this is working for me:
countryLabel () {
const countries = require('../../plugins/countries')
return countries.find(item => item.value === this.content.country).label
}

Related

How we can sort table as custom ordered values?

I want to sort the table based on custom values as below how we can write the logic for this from react side?
Order is
no s, no c, ready, pub
as I want to sort the below data
const data = [
{
name: 'Harry',
sort: 'no c',
},
{
name: 'Don',
sort: 'no s',
},
{
name: 'Arc',
sort: 'pub',
},
{
name: 'Park',
sort: 'ready',
},
];
You can create an array of sort value in order that you want to sort data, then use filter function to get those value and push it to output array.
E.g.
let output = []
let order = ['no s','no c','pub','ready']
const data = [ { name: 'Harry', sort: 'no c', }, { name: 'Don', sort: 'no s', }, { name: 'Arc', sort: 'pub', }, { name: 'Park', sort: 'ready', }]
for(const o of order){
output.push(...data.filter(d=>d.sort === o))
}
console.log(output)
const arr = [
{ name: 'Harry', sort: 'no c', },
{ name: 'Don', sort: 'no s', },
{ name: 'Arc', sort: 'pub', },
{ name: 'Park', sort: 'ready', },
];
const order = [ 'no s', 'no c', 'ready', 'pub'];
const orderedArr = [];
order.forEach(element => {
const item = arr.find((obj) => obj.sort === element);
orderedArr.push(item);
});
This solution will sort an array of any length, so long as each element has a sort property.
data.sort((obj1, obj2) => {
const order = ['no s', 'no c', 'ready', 'pub'];
const getOrder = (obj) => order.findIndex(item => item === obj.sort);
return getOrder(obj1) - getOrder(obj2);
}
EDIT:
I made the function cleaner by removing a bulky switch statement and an unnecessary variable.
Note that you need to guarantee each sort value is valid for this solution, otherwise the object will be placed at the front of the array. If you want different behavior for invalid values, you can handle that in the getOrder function if you want invalid ones at the end, or if you want to filter them out altogether, you can just tack on a .filter(obj => order.includes(obj.sort)).

Javascript: Check if duplicate key exist, Add corresponding children for the duplicate key

I am trying to figure out a sample array of object in which I have following key value pair. I need to find key which I am splitting based on underscore, first splitted value will become key and second will become the array of object of that key. I am getting duplicate key which needs to be unique and then add values into it.
const arr = [
{label: 'id', key: 'wfc_id'},
{label: 'Name', key: 'wfc_name'},
{label: 'Age', key: 'wfc_age'},
{label: 'id', key: 'ga_id'},
{label: 'Name', key: 'ga_name'},
{label: 'Age', key: 'ga_age'},
{label: 'Name', key: 'rtc_name'},
{label: 'id', key: 'rtc_id'},
]
Desired Ouput:
output = {
wfc: {id:true, name:true, age: true},
ga: {id:true, name:true, age: true},
rtc: {id:true, name:true},
}
I tried following code:
let output = Object.assign({},arr.map((item) => {
let str = item.key.split('_');
let obj = {};
obj[str[0]] = {
[str[1]]: true
}
return obj
})
);
console.log(output);
But it giving me output as
{
"0": {
"wfc": {
"id": true
}
},
"1": {
"wfc": {
"name": true
}
},
"2": {
"wfc": {
"age": true
}
},
"3": {
"ga": {
"id": true
}
},
"4": {
"ga": {
"name": true
}
},
"5": {
"ga": {
"age": true
}
},
.......
}
I require if key already exits then add array/object for it's corresponding key
The map() function returns a new array. To transform the output, you need to reduce(), also called a "fold."
arr.reduce((acc, curr) => {
const split = curr.key.split('_');
const identifier = split[0];
const property = split[1];
acc[identifier] = { ...acc[identifier], [property]: true };
return acc;
}, {});
You're better off using reduce in this case. You present it with an initial object (accumulator), and then add to it over the iterations.
const arr = [
{label: 'id', key: 'wfc_id'},
{label: 'Name', key: 'wfc_name'},
{label: 'Age', key: 'wfc_age'},
{label: 'id', key: 'ga_id'},
{label: 'Name', key: 'ga_name'},
{label: 'Age', key: 'ga_age'},
{label: 'Name', key: 'rtc_name'},
{label: 'id', key: 'rtc_id'},
]
const output = arr.reduce((acc, item) => {
// Destructure the array into a key and value
let [ key, value ] = item.key.split('_');
// If the key doesn't exist on the accumulator
// add an empty object
acc[key] = acc[key] || {};
// And then set the object property to true
acc[key][value] = true;
// Return the accumulator for the next iteration
return acc;
}, {});
console.log(output);
You may use reduce for your case.
const arr = [
{ label: "id", key: "wfc_id" },
{ label: "Name", key: "wfc_name" },
{ label: "Age", key: "wfc_age" },
{ label: "id", key: "ga_id" },
{ label: "Name", key: "ga_name" },
{ label: "Age", key: "ga_age" },
{ label: "Name", key: "rtc_name" },
{ label: "id", key: "rtc_id" },
];
const o = arr.reduce((a, b) => {
const [key, prop] = b.key.split("_");
a[key] ? (a[key][prop] = true) : (a[key] = { [prop]: true });
return a;
}, {});
console.log(o);

How to select multiple specific property with distinct value from javascript array

Suppose I have a Javascript array like below.
const data = [
{ group: 'A', name: 'SD', testid:1},
{ group: 'B', name: 'FI',testid:2 },
{ group: 'A', name: 'MM', testid:1 },
{ group: 'B', name: 'CO', testid:2 },
{ group: 'A', name: 'QW', testid:1 }
];
I want to get two specific properties(group and testid).
I would like to retrieve unique values for those properties in my end result.
So my end result will be
{group:A,testid:1},{group:B,testid:2}
What I have tried so far is below.
data.map(item=>item.group).
But this will give me only one property and without any distinct values
How can I achieve this using latest ecmascript syntax in Javascript
you can reduce the array and check every time if the pair exists:
data.reduce((prev, el) =>{
if(prev.some(o => o.group == el.group && o.testid == el.testid))
return prev;
return [...prev, {group:el.group, testid:el.testid}]
}, [])
const data = [
{ group: 'A', name: 'SD', testid:1},
{ group: 'B', name: 'FI',testid:2 },
{ group: 'A', name: 'MM', testid:1 },
{ group: 'B', name: 'CO', testid:2 },
{ group: 'A', name: 'QW', testid:1 }
];
let result = data.reduce((prev, el) =>{
if(prev.some(o => o.group == el.group && o.testid == el.testid))
return prev;
return [...prev, {group:el.group, testid:el.testid}]
}, []);
console.log(result);
You can loop over it and get the desired result.
result = []
data.forEach(x=>{
if(!result.some(y=>y.group===x.group && x.testid===y.testid)){
result.push({group:x.group,testid:x.testid});
}
});
Use forEach loop and build an object with keys as uniq_id.
After the traverse, return Object.values of the above object.
const convert = (arr) => {
const res = {};
arr.forEach(({group, testid}) => {
// change uniq_id based on requirement
const uniq_id = `${group}-${testid}`;
res[uniq_id] = { group, testid};
});
return Object.values(res);
}
const data = [
{ group: 'A', name: 'SD', testid:1},
{ group: 'B', name: 'FI',testid:2 },
{ group: 'A', name: 'MM', testid:1 },
{ group: 'B', name: 'CO', testid:2 },
{ group: 'A', name: 'QW', testid:1 }
];
console.log(convert(data));

JavaScript: How can I change property names of objects in an array?

I am using this react-select: https://github.com/JedWatson/react-select
The format for options data that they require is:
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry'},
{ value: 'vanilla', label: 'Vanilla' }
];
My array is set up differently as follows:
const columns = [
{ name: 'OrderNumber', title: 'Order Number' },
{ name: 'strawberry', title: 'Strawberry' },
{ name: 'vanilla', title: 'Vanilla' }
]
I am not able to change my array. If try to use name or value in my option items, I encounter issues using them with select-react. If I change my name to value, the select options are populating, however I don't want to do that.
Can anyone teach me how can I change my array's name to value?
You could use the .map() function to make the data in columns suitable for use with react-select.
The .map() function is available on the Array type. It creates a new array from the array you call it on, and allows you to provide a function that transforms/changes each item as it is copied from the original array.
You can make use of it as follows:
const columns = [
{ name: 'OrderNumber', title: 'Order Number' },
{ name: 'strawberry', title: 'Strawberry' },
{ name: 'vanilla', title: 'Vanilla' }
]
const options = columns.map(function(row) {
// This function defines the "mapping behaviour". name and title
// data from each "row" from your columns array is mapped to a
// corresponding item in the new "options" array
return { value : row.name, label : row.title }
})
/*
options will now contain this:
[
{ value: 'OrderNumber', label: 'Order Number' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' }
];
*/
For more information, see the MDN documentation for .map()
If you just want to rename the name property to value you can use a map and destruct the name property as value and pick the rest.
const columns = [
{ name: 'OrderNumber', title: 'Order Number' },
{ name: 'strawberry', title: 'Strawberry' },
{ name: 'vanilla', title: 'Vanilla' }
];
const newColumns = columns.map( item => {
const { name: value, ...rest } = item;
return { value, ...rest }
}
);
console.log( newColumns );
But, I suspect that you would want this since react-select doesn't work (as far as I see) with title. It waits for a label prop I guess. If this is so, go with and change all the properties as #Dacre Denny suggested. I like arrow functions :) So:
const newColumns = columns.map( item =>
( { value: item.name, label: item.title } )
);
Use destructuring with renaming property will simplify.
const options = [
{ value: "chocolate", label: "Chocolate" },
{ value: "strawberry", label: "Strawberry" },
{ value: "vanilla", label: "Vanilla" },
];
const columns = options.map(({ value: name, label: title }) => ({
name,
title,
}));
console.log(columns);

Merge Array of Objects by Property using Lodash

I have two arrays of objects that represent email addresses that have a label and a value:
var original = [
{
label: 'private',
value: 'private#johndoe.com'
},
{
label: 'work',
value: 'work#johndoe.com'
}
];
var update = [
{
label: 'private',
value: 'me#johndoe.com'
},
{
label: 'school',
value: 'schhol#johndoe.com'
}
];
Now I want to compare and merge the two arrays by the label field, so that the result would look like this:
var result = [
{
label: 'private',
value: 'me#johndoe.com'
},
{
label: 'work',
value: 'work#johndoe.com'
},
{
label: 'school',
value: 'schol#johndoe.com'
}
]
How can I do this e.g. using lodash?
_.unionBy():
This method is like _.union except that it accepts iteratee which is invoked for each element of each arrays to generate the criterion by which uniqueness is computed. Result values are chosen from the first array in which the value occurs.
var original = [
{ label: 'private', value: 'private#johndoe.com' },
{ label: 'work', value: 'work#johndoe.com' }
];
var update = [
{ label: 'private', value: 'me#johndoe.com' },
{ label: 'school', value: 'schol#johndoe.com' }
];
var result = _.unionBy(update, original, "label");
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
Convert the lists to objects keyed by label, merge them by _.assign, and convert it back to an array. It will even retain order of the items on most browsers.
var original = [
{
label: 'private',
value: 'private#johndoe.com'
},
{
label: 'work',
value: 'work#johndoe.com'
}
];
var update = [
{
label: 'private',
value: 'me#johndoe.com'
},
{
label: 'school',
value: 'schol#johndoe.com'
}
];
console.log(
_.map(
_.assign(
_.mapKeys(original, v => v.label),
_.mapKeys(update, v => v.label)
)
)
);
// or remove more duplicated code using spread
console.log(
_.map(
_.assign(
...[original, update].map(
coll => _.mapKeys(coll, v => v.label)
)
)
)
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.js"></script>
Perhaps a bit late, but all the solutions I have seen don't join both arrays correctly, they use one of the arrays to loop on and any excess elements in the second array don't get added (assuming this is what is required).
The right way is to sort both arrays and move forward within both arrays, merging the matches elements and adding the missing elements from both arrays.
Please find full solution below. This also takes O(n+m) which is the best you can get (without the computational costs for sort itself). In my code I already got the data sorted from the database.
function mergeObjectsBasedOnKey(array1, array2, compareFn, mergeFn, alreadySorted) {
var array1Index = 0;
var array2Index = 0;
const merged = [];
if (!alreadySorted) {
array1.sort(compareFn);
array2.sort(compareFn);
}
while (array1Index < array1.length && array2Index < array2.length) {
var comparedValue = compareFn(array1[array1Index], array2[array2Index]);
if (comparedValue === 0) {
merged.push(mergeFn(array1[array1Index], array2[array2Index]));
array1Index++;
array2Index++;
} else if (comparedValue < 0) {
merged.push(mergeFn(array1[array1Index]));
array1Index++;
} else {
merged.push(mergeFn(array2[array2Index]));
array2Index++;
}
}
while (array1Index < array1.length) {
merged.push(mergeFn(array1[array1Index]));
array1Index++;
}
while (array2Index < array2.length) {
merged.push(mergeFn(array2[array2Index]));
array2Index++;
}
return merged;
}
const array1 = [{
"id": 10,
isArray1: true
},
{
"id": 11,
isArray1: true
},
{
"id": 12,
isArray1: true
},
];
const array2 = [{
"id": 8,
isArray2: true
},
{
"id": 11,
isArray2: true
},
{
"id": 15,
isArray2: true
},
];
const result = mergeObjectsBasedOnKey(array1, array2, function(a, b) {
return a.id - b.id;
}, function(a, b) {
if (b) {
return _.merge(a, b);
}
return _.merge(a, {
isArray1: true,
isArray2: true
});
});
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
And the results would be:
[ { id: 8, isArray2: true, isArray1: true },
{ id: 10, isArray1: true, isArray2: true },
{ id: 11, isArray1: true, isArray2: true },
{ id: 12, isArray1: true, isArray2: true },
{ id: 15, isArray2: true, isArray1: true } ]
In case you are using lodash 3.x where _.unionBy() was not there, you can combine _.union() and _.uniq() to get the same result.
var original = [
{ label: 'private', value: 'private#johndoe.com' },
{ label: 'work', value: 'work#johndoe.com' }
];
var update = [
{ label: 'private', value: 'me#johndoe.com' },
{ label: 'school', value: 'schol#johndoe.com' }
];
var result = _.uniq(_.union(update, original), "label");
console.log(result);
I know it is not what asked for but just in case someone stumbled up on this page here is how you do this in ramda:
var original = [
{ label: 'private', value: 'private#johndoe.com' },
{ label: 'work', value: 'work#johndoe.com' }
];
var updated = [
{ label: 'private', value: 'me#johndoe.com' },
{ label: 'school', value: 'schol#johndoe.com' }
];
unionWith(eqBy(prop('label')), updated, original);
Here is another way to merge two objects using Lodash:
let a = [{
content: 'aaa',
name: 'bbb2'
},
{
content: 'aad',
name: 'ccd'
}
];
let b = [{
content: 'aaa',
name: 'bbb'
},
{
content: 'aad1',
name: 'ccd1'
}
];
let c = [...a, ...b];
let d = _.uniq(c, function(data) {
return data.content;
})
console.log(d);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"></script>
Perhaps a bit late, but all the solutions I have seen don't join both arrays correctly, they use one of the arrays to loop on and any excess elements in the second array don't get added (assuming this is what is required).
I had the same observation so put something together myself. This is working for my use case, which is to merge each object if the value of the 'label' field matches:
const dataSetHashes = dataSets.map(dataSet => _.keyBy(dataSet, 'label'))
const resultHash = _.merge(
{},
...dataSetLookups
)
const result = Object.values(resultLookup)

Categories