react native turn object array into string array - arrays

I am searching for a while now, how I could achieve to turn objects arrays into an array with only values. For example, I have an array with several Restaurants and within these restaurants there is a key named category. Category could have multiple values like Sushi, Chinese, asian. I would like to go trough all object and reduce my array from:
[{
id: '1',
title: 'Italian Dream',
category: 'Pizza, Pasta, Snack',
opening_hours: '08:00-24:00',
},
{
id: '2',
title: 'Turkish Man',
category: 'Döner, Pizza, Lahmacun',
opening_hours: '08:00-24:00',
}]
to
[ Pasta, Snack, Döner, Pizza, Lahmacun]
Would be glad if anybody could give me any advice.
Cheers

Since category is a string and not an array of strings, we need to .split(', ')
Since we have multiple categories per data item, we can use .flatMap to "combine" or flatten that what would have been an array of arrays
We can use new Set(...) to get a unique list of string values
And finally use Array.from(...) to convert the Set to an Array.
const data = [{
id: '1',
title: 'Italian Dream',
category: 'Pizza, Pasta, Snack',
opening_hours: '08:00-24:00',
},
{
id: '2',
title: 'Turkish Man',
category: 'Döner, Pizza, Lahmacun',
opening_hours: '08:00-24:00',
}
]
const categories = Array.from(new Set(data.flatMap(x => x.category.split(', '))))
console.log(categories)

You can loop your array and use split function to extract categories from your string.
let newArray = [];
oldArray.forEach(restaurant => {
newArray.push(...restaurant.category.split(', '));
});
// Here newArray contains categories with duplicate values
// You can use Set to avoid duplicate values.
newArray = [...new Set(newArray)];

Related

Subscribe to an observable and put values into an array

I'm new in angular and I need some help.
I have an observable getting users of type User[]
User: [
id: string,
name: string
]
and I have another array Ids of type string getting the ids of the selected users from a mat-select
Ids = this.Form.controls['users'].value
what I need right now is to subscribe to users$ observable, and get only the users that they have an id in Ids
const selectedUsers = ids.forEach(id =>this.usersSub$.value.filter((user) => user.userId === id))
something like the above but it is not really the right thing to do because it returns undefined . I'm wondering how should I properly get my selectedUsers array.
You use combineLatest to merge both observables and map all elements to accomplish it.
First, Create an observable with ids.
selectedIds$ = of([1, 3]);
players$ = of([
{ id: 1, name: 'lebron' },
{ id: 2, name: 'irving' },
{ id: 3, name: 'love' },
]);
Next, combine both observables, using the combineLatest operator, and return the players using the map to iterate over the response from the combineLast, use the filter and find to match the playerid with the ids from the selectedIds array.
const seletedUsers$ = combineLatest([this.selectedIds$,
this.players$])
.pipe(
map(([ids, players]) => {
return players.filter((p) => ids.find((id) => id === p.id));
})
)
.subscribe((v) => {
console.log(v);
});
https://rxjs.dev/api/index/function/combineLatest
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

Collect unique values of array in an array React

Can someone let me know how I can create a list of unique languages from an array inside another array.
This is the dataset...
const people = [
{
//Other values, name date etc.
languages: ["English", "Spanish"]
},{
//Other values, name date etc.
languages: ["English", "Mandarlin"]
},{
//Other values, name date etc.
languages: ["Japanese"]
},....
and here is as far as I've got....
const languagesOptions = this.props.data.map((item, index) => {
new Map(
...item.languages.map(d => [d.languages])
)
});
I can use the new Map function when it's not an array but can't get it to work with the languages data.
Thanks
You could map over it and use Set to remove dupes.
const people = [{
languages: ["English", "Spanish"]
}, {
languages: ["English", "Mandarlin"]
}, {
languages: ["Japanese"]
}];
const languages = [...new Set(people.flatMap(({ languages }) => languages))];
console.log(languages);

How to convert an array of dictionaries into an array of keys using react

Given a list:
let names = [{name: "bobby"}, {name: "sydney"}, {name: "Paul"}, {name: "Grace"}
I want the output to be ["bobby", "sydney", "Paul", "Grace"]
Here is what I have tried:
var items = Object.keys(names).map(function(i) {
return names[i];
})
const items = Object.keys(names).map((key)=>names[key]);
this.setState({items});
console.log(this.state.items);
names.map(({ name }) => name)
const names = [{
name: "bobby"
}, {
name: "sydney"
}, {
name: "Paul"
}, {
name: "Grace"
}];
const keys = names.map(({
name
}) => name);
console.log(keys);
A note about react keys, they should be unique within the rendered siblings, i.e. they should be unique within the dataset. Names alone may not provide sufficient uniqueness.
A second note, you might not want to generate your react keys separately from where you need them, i.e. generally they are created when you are mapping JSX.
This is not really related to React. You can do that with JavaScript, for instance using API like map().
Here is an example:
let arr = names.map(obj => obj.name);

Multidimensional Arrays, Vuex & Mutations

I'm attempting to both add and remove items in a multidimensional array stored in Vuex.
The array is a group of categories, and each category and have a sub-category (infinity, not simply a two dimensional array).
Example data set is something like this:
[
{
id: 123,
name: 'technology',
parent_id: null,
children: [
id: 456,
name: 'languages',
parent_id: 123,
children: [
{
id:789,
name: 'javascript',
parent_id: 456
}, {
id:987,
name: 'php',
parent_id: 456
}
]
}, {
id: 333,
name: 'frameworks',
parent_id 123,
children: [
{
id:777,
name: 'quasar',
parent_id: 333
}
]
}
]
}
]
....my question is, how do I best add and remove elements to this array, which is inside of a Vuex Store?
I normally manipulate simple arrays inside the Vuex Store using Vue.Set() to get reactivity. However, because I'm not sure how deep the nested array being manipulated is - I simply can't figure it out.
Here's an example of how I thought I could add a sub-category element using recursion:
export const append = (state, item) => {
if (item.parent_uid !== null) {
var categories = []
state.data.filter(function f (o) {
if (o.uid === item.parent_uid) {
console.log('found it')
o.push(item)
return o
}
if (o.children) {
return (o.children = o.children.filter(f)).length
}
})
} else {
state.data.push(item)
}
}
The first thing to understand is that vuex, or any other state management library based on flux architecture, isn't designed to handle nested object graph, let alone arbitrary/infinity nested objects that you mentioned. To make the matter worse, even with shallow state object, vuex works best when you define the shape of the state (all desired fields) upfront.
IMHO, there are two possible approaches you can take
1. Normalize your data
This is an approach recommended by vue.js team member [here][2].
If you really want to retain information about the hierarchical structure after normalization, you can use flat in conjunction with a transformation function to flatten your nested object by name to something like this:
const store = new Vuex.Store({
...
state: {
data: {
'technology': { id: 123, name: 'technology', parent_id: null },
'technology.languages': { id: 456, name: 'languages', parent_id: 123 },
'technology.languages.javascript': { id: 789, name: 'javascript', parent_id: 456 },
'technology.languages.php': { id: 987, name: 'php', parent_id: 456 },
'technology.frameworks': { id: 333, name: 'frameworks', parent_id: 123 },
'technology.frameworks.quasar': { id: 777, name: 'quasar', parent_id: 333 },
}
},
});
Then you can use Vue.set() on each item in state.data as usual.
2. Make a totally new state object on modification
This is the second approach mentioned in vuex's documentation:
When adding new properties to an Object, you should either:
Use Vue.set(obj, 'newProp', 123), or
Replace that Object with a fresh one
...
You can easily achieve this with another library: object-path-immutable. For example, suppose you want to add new category under languages, you can create a mutation like this:
const store = new Vuex.Store({
mutations: {
addCategory(state, { name, id, parent_id }) {
state.data = immutable.push(state.data, '0.children.0.children', { id, name, parent_id });
},
},
...
});
By reassigning state.data to a new object each time a modification is made, vuex reactivity system will be properly informed of changes you made to state.data. This approach is desirable if you don't want to normalize/denormalize your data.

Using Object.assign with Observable Array

I'm using Object.assign to add an attribute to each element of an Observable Array
Struggling figuring out the right operators to add an attribute to each object of the array. For example, in this case the name field was used inappropriately for grade.
Example:
let x = Observable.of({id: 1, name: first grader}, {id: 2, name: second grader})
// current solution using flatmap and then re-configuring as array
x
.flatMap( res => res.map( student => Object.assign({}, student, {grade: student.name})))
.toArray()
The above example works, but seems strange...as I'm flatmapping and then re-constituting the array. Is there a better operator/ approach to reduce the steps?
If I just use Object.assign on the initial observable I get:
Object {0: Object, 1: Object}, which is an object of objects rather than an array of objects.
The above example works, but seems strange...as I'm flatmapping and
then re-constituting the array. Is there a better operator/ approach
to reduce the steps?
If your data is already available as an array then you can mutate the complete array yourself:
Rx.Observable.of([{id: 1, name: 'first grader'}, {id: 2, name: 'second grader'}])
.map(students => {
// note - this map below is Array.prototype.map, not Rx
return students.map(student => Object.assign({}, student, {grade: student.name}));
})
.subscribe(x => console.log(x));
But Rx really shines when your data is received async:
Rx.Observable.from([{id: 1, name: 'first grader'}, {id: 2, name: 'second grader'}]) /* stream of future student data elements */
.map(student => Object.assign({}, student, {grade: student.name}))
.toArray() // combine your complete stream when completed into a single array emission
.subscribe(x => console.log(x));
The toArray() is a utility function to wait for completion and then return all emitted elements inside an array as the first (and final) emission.
If you run your code as it is it will fail. Because if you pass multiple objects to Observable.of it will push them into stream one by one.
So I assume what you meant is
Rx.Observable.of([{id: 1, name: 'first grader'}, {id: 2, name: 'second grader'}])
note the square brackets.
To achieve what you want you can use map operator:
Rx.Observable.of([{id: 1, name: 'first grader'}, {id: 2, name: 'second grader'}])
.map(res => res.map( student => Object.assign({}, student, {grade: student.name})))
.subscribe(x => console.log(x));
See jsBin

Resources