How to iterate array with an array object in React Native - javascript

I'm starting to program in React Native and I have an array like this:
state = {
territories: [
{
id: 1,
number: 1,
title: 'Territory 1',
streets: [
{
id: 1,
name: 'Name of street 1',
houses: [
{
id: 1,
number: '11',
},
{
id: 2,
number: '689',
},
{
id: 3,
number: '117a',
},
],
},
{
id: 2,
nome: 'Name of street 2',
houses: [
{
id: 4,
number: '02',
},
{
id: 5,
number: '655',
},
{
id: 6,
number: '11b',
},
],
},
],
},
],
};
And I want to iterate it with .map() function in order to create a Section List like this example
But I can't iterate house's number array within streets array.
Is there a way to do that with React Native?
Thank you very much in advance

You need a map to iterate through the territories then through streets and houses.
Copy paste the code in codesandbox.io react sandbox. You can fix the html to use a table
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
const state = {
territories: [
{
id: 1,
number: 1,
title: "Territory 1",
streets: [
{
id: 1,
name: "Name of street 1",
houses: [
{
id: 1,
number: "11"
},
{
id: 2,
number: "689"
},
{
id: 3,
number: "117a"
}
]
},
{
id: 2,
name: "Name of street 2",
houses: [
{
id: 4,
number: "02"
},
{
id: 5,
number: "655"
},
{
id: 6,
number: "11b"
}
]
}
]
}
]
};
function App() {
return state.territories.map(territory => {
return territory.streets.map(street => {
return (
<div>
<p>{street.name}</p>
{street.houses.map(house => <div>{house.number} </div>)}
</div>
);
});
});
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

I would start by writing a streetRender function, which will get a single street object and render it, by doing street.map, iterating by house. This should be a simple map call.
Now I would write a territoryRender function, which gets a single territory, performing territory.map, iterating by street, and for each street perform
return (streetRender(street));
Last step will be to perform territories.map, and for each territory perform
return (territoryRender(territory))

Related

Filter array of objects dynamically according to another array of objects

So I am making a filter functionality for React, so I have an array of objects, and based on another array that contains values to filter the array, I need to get the filtered values.
code: the array of objects to apply the filter to:
const citiesData = [
{
id: 1,
name: 'amritsar',
popu: '1200'
},
{
id: 2,
name: 'jalandhar',
popu: '1300'
},
{
id: 3,
name: 'phagwara',
popu: '1200'
},
{
id: 4,
name: 'ludhiana',
popu: '1400'
},
{
id: 5,
name: 'mumbai',
popu: '2000'
},
{
id: 6,
name: 'banglore',
popu: '2000'
},
{
id: 7,
name: 'ohter city 1',
popu: '1500'
},
{
id: 8,
name: 'ohter city 2',
popu: '1500'
},
{
id: 9,
name: 'anohter city 1',
popu: '2200'
},
{
id: 10,
name: 'anohter city 2',
popu: '2200'
},
]
code: filters array based on what I need to apply the conditions:
const filterCity = [
{
filterType: 'name',
filterValue: 'amritsar'
},
{
filterType: 'popu',
filterValue: '1200'
}
]
solutions I've tried:-
code: solution 1:
const filteredList = citiesData.filter(item => {
return filterCity.filter(fItem => item[fItem.filterType] === fItem.filterValue).length
})
code: solution 2:
const filteredList = citiesData.filter(item => {
return filterCity.reduce((acc, val) => {
if(item[val.filterType] === val.filterValue) {
acc = true
}
return acc;
}, false)
})
code: result I'm getting:
[
{ id: 1, name: 'amritsar', popu: '1200' },
{ id: 3, name: 'phagwara', popu: '1200' }
]
it's giving me two objects because according to the filters array I'm searching for the name and popu fields. but the expected result should be:
[ { id: 1, name: 'amritsar', popu: '1200' } ]
because the name and popu is similar in that but in the second object the name is not the same.
I want the code to check all the conditions and then give me the result. right now it's working on the individual filter and individual array item.
so can anyone help me on this!!
so, it should be an AND filter (combining all conditions)?
res = citiesData.filter(d =>
filterCity.every(f => d[f.filterType] === f.filterValue))
for the OR filter (any condition), replace every with some.

Group array of objects by multiple nested values

I have an array of objects which presents tasks. These tasks are categorized (primary / secondary category).
let tasks = [
{
id: 1,
name: 'Cleanup desk',
primary_category: {
id: 1,
name: 'Indoor'
},
secondary_category: {
id: 2,
name: 'Surfaces'
}
},
{
id: 2,
name: 'Cleanup office floors',
primary_category: {
id: 1,
name: 'Indoor'
},
secondary_category: {
id: 3,
name: 'Ground'
}
},
{
id: 3,
name: 'Water plants',
primary_category: {
id: 2,
name: 'Outdoor'
},
secondary_category: {
id: 3,
name: 'Irrigation'
}
}
];
I now try to create a categories accordion in my frontend and therefore need to group my array differently. The structure should look like:
1) primary category
> secondary category
> tasks
> secondary category
> tasks
2) primary category
> secondary category
> tasks
Therefore I'm trying to achieve a structure similar to this:
let tasks_categorized = [
{
id: 1,
name: 'Indoor',
secondary_categories: [
{
id: 2,
name: 'Surfaces',
tasks: [
{
id: 1,
name: 'Cleanup desk'
}
]
},
{
id: 3,
name: 'Ground',
tasks: [
{
id: 2,
name: 'Cleanup office floors'
}
]
}
]
},
{
id: 2,
name: 'Outdoor',
secondary_categories: [
{
id: 3,
name: 'Irrigation',
tasks: [
{
id: 3,
name: 'Water plants'
}
]
}
]
}
];
I tried using groupBy by lodash but this does not allow grouping by multiple nested key-value pairs. Does anybody know an approach to solve this?
Thank you in advance!
The following provided approach is going to achieve the expected result within a single reduce cycle without any further nested loops.
It does so by implementing a reducer function which creates and/or aggregates at time a prioritized category task while iterating another task array. But most importantly it keeps track of a task item's related primary and secondary categories via a Map based lookup. This lookup reference together with a result array are properties of this function's return value which has to be partly provided as the reduce method's initial value as follows ... { result: [] }.
function createAndAggregatePrioritizedCategoryTask(
{ lookup = new Map, result }, item
) {
const { primary_category, secondary_category, ...taskRest } = item;
const { id: primaryId, name: primaryName } = primary_category;
const { id: secondaryId, name: secondaryName } = secondary_category;
const primaryKey = [primaryId, primaryName].join('###');
const secondaryKey = [primaryKey, secondaryId, secondaryName].join('###');
let primaryCategory = lookup.get(primaryKey);
if (!primaryCategory) {
// create new primary category item.
primaryCategory = {
id: primaryId,
name: primaryName,
secondary_categories: [],
};
// store newly created primary category reference in `lookup`.
lookup.set(primaryKey, primaryCategory);
// push newly created primary category reference to `result`.
result.push(primaryCategory);
}
let secondaryCategory = lookup.get(secondaryKey);
if (!secondaryCategory) {
// create new secondary category item.
secondaryCategory = {
id: secondaryId,
name: secondaryName,
tasks: [],
};
// store newly created secondary category reference in `lookup`.
lookup.set(secondaryKey, secondaryCategory);
// push newly created secondary category reference into the
// `secondary_categories` array of its related primary category.
primaryCategory
.secondary_categories
.push(secondaryCategory);
}
// push the currently processed task-item's rest-data as
// item into the related secondary category's `task` array.
secondaryCategory
.tasks
.push(taskRest);
return { lookup, result };
}
let tasks = [{
id: 1,
name: 'Cleanup desk',
primary_category: { id: 1, name: 'Indoor' },
secondary_category: { id: 2, name: 'Surfaces' },
}, {
id: 2,
name: 'Cleanup office floors',
primary_category: { id: 1, name: 'Indoor' },
secondary_category: { id: 3, name: 'Ground' },
}, {
id: 3,
name: 'Water plants',
primary_category: { id: 2, name: 'Outdoor' },
secondary_category: { id: 3, name: 'Irrigation' },
}];
const { result: tasks_categorized } = tasks
.reduce(createAndAggregatePrioritizedCategoryTask, { result: [] });
console.log({ tasks_categorized });
.as-console-wrapper { min-height: 100%!important; top: 0; }
You could take a dynamic approach with an array of arrays with functions and keys for the nested arrays.
const
tasks = [{ id: 1, name: 'Cleanup desk', primary_category: { id: 1, name: 'Indoor' }, secondary_category: { id: 2, name: 'Surfaces' } }, { id: 2, name: 'Cleanup office floors', primary_category: { id: 1, name: 'Indoor' }, secondary_category: { id: 3, name: 'Ground' } }, { id: 3, name: 'Water plants', primary_category: { id: 2, name: 'Outdoor' }, secondary_category: { id: 3, name: 'Irrigation' } }],
groups = [
[o => o, 'primary category'],
[o => o.primary_category, 'secondary category'],
[o => o.secondary_category, 'tasks']
],
result = tasks.reduce((r, o) => {
groups.reduce((parent, [fn, children]) => {
const { id, name } = fn(o);
let item = (parent[children] ??= []).find(q => q.id === id)
if (!item) parent[children].push(item = { id, name });
return item;
}, r);
return r;
}, {})[groups[0][1]];
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

How do I check that the correct objects are being returned via a function (expect function returns [Function Anonymous])?

I have a function:
const sort =
(pets,attribute) =>
_(pets)
.filter(pets=> _.get(pets, attribute) !== null)
.groupBy(attribute)
.value()
Some data:
const pets= [{
id: 1,
name: 'snowy',
},
{
id: 2,
name: 'quacky',
},
{
id: 3,
name: 'snowy',
age: 5,
},
{
id: null,
name: null,
age: null
}
]
const attribute = 'name'
I am currently trying to write some Jest unit tests for this, that tests if the function returns the correct resultant object after being sorted based off an attribute.
The result of:
sort(pets,attribute) is something like this:
{
snowy: [ { id: 1, name: 'snowy' }, { id: 3, name: 'snowy', age: 5} ],
quacky: [ { id: 2, name: 'quacky' } ]
}
Is there a way I can do a expect to match the two objects snowy and quacky here?
The thing I want to test for is that the objects are being correctly grouped by the key.
I've tried using something like
const res = sort(users,key)
expect(res).toEqual(
expect.arrayContaining([
expect.objectContaining({'snowy' : [ { id: 1, name: 'snowy' }, { id: 3, name: 'snowy', age: 5 } ]},
expect.objectContaining({'quacky' : [ { id: 2, name: 'quacky' } ]}))
])
)
which doesn't seem to work, the received output seems to output:
Expected: ArrayContaining [ObjectContaining {"snowy": [{"id": 1, "name": "snowy"}, {"age": 5, "id": 3, "name": "snowy"}]}]
Received: [Function anonymous]
I am unsure what the best method to test this kind of function is either so advice on that would be appreciated.
If this is what your arrangeBy() returns:
{
snowy: [ { id: 1, name: 'snowy' }, { id: 3, name: 'snowy', age: 5} ],
quacky: [ { id: 2, name: 'quacky' } ]
}
Then you can just do:
const expected = {
snowy: [ { id: 1, name: 'snowy' }, { id: 3, name: 'snowy', age: 5} ],
quacky: [ { id: 2, name: 'quacky' } ]
}
const res = arrangeBy(users,key)
expect(res).toEqual(expected)
But looking at your Error message I guess you have something else mixed up. In the beginning you listed the implementation of a sort function which seems to not be used in the test. Where is arrangeBy coming from now.
Please provide more code examples.

Vuetify TreeView Data Manipulation

I am trying to use v-treeview to create a nested list of items. This list of items could be 10 layers deep or 100, each with 100 items within. How would I go about turning a few hundred objects into one large object with children nested within children?
Starting Data (2 or more objects):
[
{
id:1 ,
name: "hot-dog",
children: [
{name:"meat"}
]
},
{
id:2 ,
name: "meat",
children: [
{name:"salt"}
{name:"horse-meat"}
]
}
]
Desired Data (one master object):
[
{
id:1 ,
name: "hot-dog",
children: [
{
id:2 ,
name: "meat",
children: [
{name:"salt"}
{name:"horse-meat"}
]
}
]
}
]
It seems that you want to rearrange those items to be displayed as a tree view.
As you've posted, each of then are displayed as objects in a flat array, like the following:
[
{ id: 1, name: "hot-dog",
children: [ { name: "meat" } ] },
{ id: 2, name: "meat",
children: [ { name: "salt" }, { name: "horse-meat" } ] },
{ id: 3, name: "salt" },
{ id: 4, name: "horse-meat" },
];
And need to be transformed into a array of master objects.
I've written a MRE that can display it working. Also, see this working example on codepen.
<div id="app">
<v-app id="inspire">
<v-treeview :items="formattedItems"></v-treeview>
</v-app>
</div>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
items: [
{
id: 1,
name: "hot-dog",
children: [
{name:"meat"},
],
},
{
id: 2,
name: "meat",
children: [
{name:"salt"},
{name:"horse-meat"},
],
},
{
id: 3,
name: "pancake",
children: [
{name: "honey"},
]
},
{
id: 4,
name: "honey",
},
{
id: 5,
name: "salt",
},
{
id: 6,
name: "horse-meat",
},
]
}),
computed: {
formattedItems() {
const mapper = function (current) {
let child = this.find(item => item.name === current.name);
if (child.children) {
child.children = child.children.map(mapper, this);
}
return child;
};
const reducer = (accum, current, index, array) => {
if (!array.find(item => !!item.children && item.children.find(child => child.name === current.name))) {
current.children = current.children.map(mapper, array);
accum.push(current);
}
return accum;
};
return this.items.reduce(reducer, []);
}
}
})

ReactJS - Swap out all the values in an array of objects in state with another array

I am trying to swap out all the values of an array of objects in state with a whole new array of objects. However, nothing seems to be working. I've tried the following:
const list1 = [
{ id: 1, name: 'item1' },
{ id: 2, name: 'item1' },
{ id: 3, name: 'item1' },
{ id: 4, name: 'item1' },
]
const list2 = [
{ id: 1, name: 'newItem1' },
{ id: 2, name: 'newItem2' },
{ id: 3, name: 'newItem3' },
{ id: 4, name: 'newItem4' },
]
class FindTab extends Component {
state = {
status: 'loading',
location: null,
view: this.props.view,
map: this.props.map,
locationValues: list1,
}
}
this.setState(prevState => ({
locationValues: [ ...prevState.locationValues, list2 ],
}))
or just simpler:
this.setState(locationValues: list2)
Neither seem to work. Is there any guidance as to how one should replace an array of objects with another array for a state property?
You could spread the array in a new one like:
const locationValues = [ ...state.locationValues, ...list2 ]
this.setState({ locationValues })

Categories

Resources