Select certain values and sort alphabetically in ES6 - javascript

How can I select on certain values and sort them alphabetically using ES6.
The current codes defines a constant. I wanted to know if I could manipulate this data without having to create a new constant with just the values I need.
export const names = {
John: 'John',
Mike: 'Mike',
David: 'David',
Chris: 'Chris'
};
Return only Chris and David.
Chris
David

const names = {
John: 'John',
Mike: 'Mike',
David: 'David',
Chris: 'Chris',
};
const searchNames = (args, search) => {
const arr = Object.values(args);
const result = arr.filter(n => {
return search.includes(n);
});
return result.sort().join('\n');
};
searchNames(names, ['David', 'Chris']);
// returns: Chris
// David
Not the most elegant, but it works. It would be easier to start with an array instead of an object. It doesn't seem like the object is necessary since the keys and values are identical. Nonetheless, this is a pretty easy task with an array. I converted the obj to an array containing only the values. Then created a new array
filtering out the names we wanted, returned that array sorted alphabetically and in a string format. The ('\n') in the return statement is just delimiting the elements of the array by a new line, since that's the format you showed. But that can be changed to anything, if you don't need the names to be on separate lines.
Just to clarify, as per the documentation, const can be used here:
The const declaration creates a read-only reference to a value. It does not mean the value it holds is immutable, just that the variable identifier cannot be reassigned.

Yes you can manipulate this data, have a look on how const works in javascrips.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
const names = {
John: 'John',
Mike: 'Mike',
David: 'David',
Chris: 'Chris'
};
console.log(names.John);
names.John = 'noJohn';
console.log(names.John);

Related

JS - How to add key:value pairs from objects nested in arrays to other objects nested in another array

I know it has been countlessly asked and I assure you that I've read a lot of posts, articles, etc., and watched a lot of videos but nothing seems to click.
so there we go :
Here are 2 arrays with partial information about every person
let arr1 = [{id:00, name:Ben, city:Philadelphia}, {id:01, name:Alice, city:Frankfurt}, {id:02, name:Detlef, city:Vienna}]
let arr2 = [{id:02, age:18}, {id:00, age:39}, {id:01, age:75}]
And there is the desired final result: an array including the name, city, and age of each person
let arr3 = [{name:Ben, city:Philadelphia, age:39}, {name:Alice, city:Frankfurt, age:75 }, {name:Detlef, city:Vienna, age:18}]
What's the situation? Two arrays both containing objects. each nested object has an id. That id is the common key in each array of objects.
What do you want to do? : I want to create a third array including information from both arrays (from arr1: name and city; from arr2:age).
What have you tried so far? : I couldn't manage to achieve anything worth showing. this minimal example is intended to show you a simple example of my current situation which is: I've got an array that is in the LocalStorage on one hand and an API on the other, both contain some info regarding particular objects (let's say, persons). I want to create an array that will contain all the information regarding each person for easier manipulation afterward (DOM generation, etc.).
I've managed to store both arrays in two "local" arrays but the problem is still there: I can't figure out how to make an array where items are getting their key/value from two separate sources.
Thank you for your help!
You can use reduce method on the arr with array as an inital value, and inside try to find the corrospending item with same id and destruct the object from the id and merge the two object with spread operator.
let arr1 = [{id:00, name:'Ben', city: 'Philadelphia' }, {id:01, name:'Alice', city:'Frankfurt'}, {id:02, name:'Detlef', city:'Vienna'}]
let arr2 = [{id:02, age:18}, {id:00, age:39}, {id:01, age:75}]
const result = arr1.reduce((acc, { id: id1, ...rest1 }) => {
const { id: id2, ...rest2 } = arr2.find(i => i.id === id1)
acc.push({ ...rest1, ...rest2 })
return acc;
}, [])
console.log(result)
You can solve it in various ways, here first I have implemented a dict with key as id to get the value in O(1) while iterating arr2.
So the overall time complexity is O(n+k) where n is len of arr1 and k is len of arr2.
let arr1 = [{id:00, name: "Ben", city: "Philadelphia"}, {id:01, name:"Alice", city:"Frankfurt"}, {id:02, name:"Detlef", city:"Vienna"}];
let arr2 = [{id:02, age:18}, {id:00, age:39}, {id:01, age:75}];
const refMapById = arr1.reduce((refMap, {id, name, city}) => {
refMap[id] = {name, city};
return refMap;
}, {});
const result = arr2.reduce((resultArray, {id, age}) => [...resultArray, { ...refMapById[id],age}], []);
console.log(result);
Cheers!
It will be worth creating a dictionary from one of the arrays anyway since using .find() inside of .reduce() adds an unnecessary nested loop. But instead of reducing the second array as was suggested you can simply .map() it into the result array, like so:
let arr1 = [{ id: 00, name: "Ben", city: "Philadelphia" }, { id: 01, name: "Alice", city: "Frankfurt" }, { id: 02, name: "Detlef", city: "Vienna" }];
let arr2 = [{ id: 02, age: 18 }, { id: 00, age: 39 }, { id: 01, age: 75 }];
const groupedById = arr1.reduce((group, person) => {
group[person.id] = person;
return group;
}, {});
const result = arr2.map((personPartFromSecondArray) => {
const personPartFromFirstArray = groupedById[personPartFromSecondArray.id];
if (typeof personPartFromFirstArray !== "undefined") {
return { ...personPartFromFirstArray, ...personPartFromSecondArray }
}
return personPartFromSecondArray;
});
console.log(result);

How to update filter array without using React?

Let's say I have some code, like this:
const filter = {
address: 'India',
name: 'Aleena'
};
const users = [{
name: 'John Doe',
email: 'johndoe#mail.com',
age: 25,
address: 'USA'
},
{
name: 'Aleena',
email: 'aleena#mail.com',
age: 35,
address: 'India'
},
{
name: 'Mark Smith',
email: 'marksmith#mail.com',
age: 28,
address: 'England'
}
];
const filteredUsers = users.filter((item) => {
for (var key in filter) {
if (item[key] === undefined || item[key] != filter[key])
return false;
}
return true;
});
How can I dynamically update/change the filter object to allow users to choose which key:values to use in the filtering process? I know people normally use React for this kind of stuff, but I wondered if there was a "vanilla" way to do it.
Actually, filter does it for you already. Filter returns a new filtered array without mutating the original array.
"Users" is the original array. "FilteredUsers" is the newly created filtered array off users.
To clone/copy the original Users array above, you can do:
let clonedArray = [...Users]
The users array is a perfect candidate for this. Let's say you want to add all of the users ages together. It's pretty cool-simple.
1- function addAges(acc,ele) {return acc + ele.age}
2- Users.reduce(addAges, 0);
That'it. No console.log either. It'll returned the sum
here's a very basic example in CodeSandBox to get an idea of what to do.
I believe it meets the requirements of your question
https://codesandbox.io/s/vanila-js-dynamic-filter-6yhhe6?file=/src/index.js

Working with list of arrays and accesing its elements in React

I'm using two objects in my app.
First type looks like this:
and I can access the gender like this: data.results[0].gender
So to elaborate on this i decided to record all people in the data array and now i have an object that looks like this:
how do I reference and access names of selected people from an object like this?
Thanks
To be fair, this seems like a poor/messy way to keep data in general, but maybe you could define a map between your people's ids or uuids or usernames, let's say, and the corresponding objects and then call them by their ids to retrieve the info you need on them:
const peopleMap = new Map();
for (person in array){
peopleMap.set(person.id.value, person)
}
ex.
let aparticularid = '92bd-asd1-24nas-213c-3cac-31ac';
let person = peopleMap.get(aparticularid);
let fullname = person.title + ' ' + person.first + ' '+ person.last;
Realistically you'd retrieve the particular id from elsewhere or some event. Or you can map names to the corresponding objects if you can guarantee their uniqueness(if they are not unique, the objects will be overridden in the map)
You can use .map() to iterate over the items of an Array.
Example -
yourArray.map(x => {
const {title, first, last} = x.name;
console.log(`${title} | ${first} } ${last}`)
})
const yourArray = [
{
id: {name: 'HETU', value: 'NAANANFSF'},
name: {title: 'Ms.', first: 'Mila', last: 'Heitet'}
},
{
id: {name: 'Tom', value: 'TANN'},
name: {title: 'Mr.', first: 'Tom', last: 'Altar'}
},
{
id: {name: 'HARRY', value: 'HARSFF'},
name: {title: 'Mr.', first: 'Harry', last: 'Krishna'}
}
];
yourArray.map(x => {
const {title, first, last} = x.name;
console.log(`${title} | ${first} | ${last}`)
})
Based on the second screenshot, this is an array of objects. Lets call the array arr then you can access the name of the i-th person in the following way:
arr[i].name.first and arr[i].name.last respectively.

Object Array to Hash Table

Would like to convert (using Ramda)
var a = [{id: 1, name: 'one'}, {id: 2, name: 'two'},{id: 3, name: 'three'}]
into
var b = {1:'one', 2:'two', 3:'three'}
I'm very new to functional programming and I am open to any ideas.
What I think we must do is, use a reduce function starting with {} and then we want to add on each iteration the id and name of the current element to the hashtable. This is what I came up with which appears very wrong. Am I close?
var a = [{id: 1, name: 'one'}, {id: 2, name: 'two'},{id: 3, name: 'three'},{id: 4, name: 'four'} ]
var b = R.reduce(R.assoc(R.prop('id'), R.prop('name')), {}, a)
b
There are many approaches to this that will work. All the other correct answers helps show that. I'll list a few of my own below. But first,
Why your approach isn't working
You try to do this:
R.reduce(R.assoc(R.prop('id'), R.prop('name')), {}, a)
It's clear what you're trying to do here. The trouble is that R.prop('id') and R.prop('name') are functions. R.assoc does not accept functions; it wants a String (Number will actually serve) and an arbitrary value. So assoc will not work with these in this manner.
One attempt to clean this up is to recognize that functions can be thought of as containers of values. In some -- perhaps surprising, but quite useful -- way, a function is a container of its return value. R.lift is meant to turn functions that work on values into ones that work on containers of values. It works like this: R.multiply accepts numbers. If we lift multiply, the resulting function accepts containers of numbers. Like this:
R.lift(R.multiply)(Maybe.Just(5), Maybe.Just(3)) // Maybe.Just(15)
If we supply lift(multiply) with two functions, then we get back a function that returns the result of multiplying their return values:
const area = R.lift(R.multiply)(prop('width'), prop('height'))
area({width: 5, height: 3})
So perhaps we could update your technique with a lift:
R.reduce(R.lift(R.assoc)(R.prop('id'), R.prop('name'), identity), {}, a)
Unfortunately, this fails again. The trouble this time is that reduce takes a binary callback, supplying both the accumulator and the current value. But R.prop('id') and R.prop('name') don't recognize that. They look for the relevant properties on the accumulator, which simply are not there.
We might still be able to fix this, but at this point, we'd be losing a great deal of the simplicity of this solution. So let's look at other possibilities.
Some solutions
Simple Reduce
Each of these two versions uses a simple reduce call, as your solution tried to do:
const convertToHash = reduce((acc, {id, name}) => merge(acc, {[id]: name}), {})
and
const convertToHash = reduce((acc, {id, name}) => ({...acc, [id]: name}), {})
They are much the same. Both create disposable objects on each iteration. In the first one, you could replace R.merge with Object.assign without any real issues, as the resulting mutation is internal to the function. The second one seems slightly more elegant, but it rebuilds the entire accumulator on each iteration. As the engine optimization for ES6 proceeds, this will likely eventually not be a performance problem, but it might be right now, especially if this is in performance-critical code.
Using zipWith
Ramda's zip functions take two lists and combine them, position by position, into a single list. R.zipWith accepts a function used to combine the two elements into one. Here we use R.objOf, which turns a name and a value into a single-property object. (objOf('foo', 42) //=> {foo: 42}.):
const convertToHash = compmose(mergeAll, lift(zipWith(objOf))(pluck('id'), pluck('name')))
As above, we use lift to make this zipWith(objOf) work with functions. That results in something like [{"1": "one"}, {"2": "two"}, {"3": "three"}], which we then pass to R.mergeAll to create a single object.
Using props and fromPairs
This solutions uses R.props and R.fromPairs. fromPairs accepts a list of name-value pairs (as two-element arrays) and turns them into a single object. props pulls the named properties into a stand-alone array. Mapping this over the original list give us the input to fromPairs:
const convertToHash = compose(fromPairs, map(props(['id', 'name'])))
Although I'm fond of the zipWith solution, and would use it if its output was what I wanted, having to add the mergeAll, makes it harder to comprehend at a glance. And so this solution wins in my mind as the best Ramda choice.
You could achieve this by the following:
var a = [{id: 1, name: 'one'}, {id: 2, name: 'two'},{id: 3, name: 'three'}]
var b = R.reduce((dict, item) => ({ ...dict, [ item.id ] : item.name }), {}, a)
This approach uses es6 syntax to add keys (named via item.id) with value (item.name) to your resulting dictionary, during each iteration of the reduction.
You can create a pipeline (R.pipe) to convert your array of objects to a hash:
Get the values of each (R.map) objects' properties (R.props).
Convert the array of pairs to an object (R.fromPairs).
const a = [{id: 1, name: 'one'}, {id: 2, name: 'two'},{id: 3, name: 'three'}];
const convertToHash = (props) =>
R.pipe(
R.map(R.props(props)),
R.fromPairs
);
const result = convertToHash(['id', 'name'])(a);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
Try using this code:
var a = [{id: 1, name: 'one'}, {id: 2, name: 'two'},{id: 3, name: 'three'}]
R.map(i=> {
var n = []
n[R.keys(i)[0]] = i.name
return n
},a)
when using es6 you can get a more flexible solution
let a = [{id: 1, name: 'one'}, {id: 2, name: 'two'},{id: 3, name: 'three'}];
let out = a.reduce((acc, {id, name}) => {
acc[id] = name;
return acc;
}, {});
console.log(out)
You can loop your initial array and assign to new object:
var a = [{id: 1, name: 'one'}, {id: 2, name: 'two'},{id: 3, name: 'three'}];
var new_a = {};
a.forEach(function(e) {
new_a[e.id] = e.name;
});
console.log(new_a);

Pulling the same value out of a series of keys

I'm trying to quickly pull out ‘value’ property from some objects using destructuring.. is there a simple way to get it from this? I think it might be possible with some complicated destructuring thing i haven’t quite grocked.
I know I could use loops and such, but I'd like to make it a bit more elegant. I'm looking for a non-repetitive, ideally 1-2 line solution. I wanted to use a map, but that only works on an array...
formData = {
name: {val: 'myName', key: 'value', etc: 'more data'}
province: {val: 'myProvince', key: 'value', etc: 'more data'}
dateOfBirth: {val: 'myBDAY!', key: 'value', etc: 'more data'}
}
//desired outcome:
{
name: 'myName',
province: 'myProvince',
dateOfBirth: 'myBDAY!'
}
//attempt 1
let customer = { name, province, dateOfBirth} = formData; //hrm doesn't get me there
Destructuring is used to assign multiple variables from different elements of an array or object, that's not what you're doing. You can just do:
let customer = {
name: formData.name.val,
province: formData.province.val,
dateOfBirth: formData.dateOfBirth.val
}
If you don't want to list all the properties explicitly, just use a loop.
let customer = {};
for (var k of Object.keys(formData)) {
customer[k] = formData[k].val;
}
A hard to read one-liner would be:
let customer = Object.keys(formData).reduce(
(acc, key) => Object.assign(acc, {[key]: formData[key].val}), {});
to grab .val off every value in the object, and return a new object with the same keys.
That's basically the equivalent of:
let customers = {};
for (const key of Object.keys(formData)) customers[key] = formData[key].val;
Since you didn't like Barmar's answer, you can use a combination of Object.keys and the resulting array's reduce method:
let customer = Object.keys(formData).reduce(function(acc, key) {
acc[key] = formData[key].val;
return acc;
}, {});
You said you wanted to use destructuring… so let's do that:
let customer = {};
for (let k in formData) ({[k]: {val: customer[k]}} = formData);
But really, avoid that, and use clear and readable property assignment instead :-)

Categories

Resources