'filtering an array based on multible conditions react native
I want to filter an array based on multiple conditions. these conditions are based on a switch and the problem is if i toggle one switch the state changes to true and i get the required result, but if i toggle two or more switches at the same time as shown in the image i get an empty array. I want to get an array with the true values of the toggled switches and discard all the false values in the MEALS array
this is the switch screen
import React,{useState} from 'react';
import {View, Text, StyleSheet, TouchableOpacity} from 'react-native';
import AnimatedLoader from "react-native-animated-loader";
import { ScrollView, Switch } from 'react-native-gesture-handler';
const Switch= ({navigation})=>{
const [loading, setLoading] = useState(false);
const [hasMeatCube, setHasMeatCube] = useState(false);
const [hasGroundMeat, setHasGroundMeat] = useState(false);
const [hasKofta, setHasKofta] = useState(false);
const [hasLiver,setHasLiver] = useState(false);
const [hasSusage, setHasSusage] = useState(false);
const [hasMeatShank, setHasMeatShank] = useState(false);
const startLoading = ()=>{
setLoading(true)
setTimeout(()=>{
navigation.navigate('FilteredList',{filteredList: {
hasMeatCube,
hasGroundMeat,
hasTurkey,
hasKofta,
hasLiver,
hasSusage,
}})
setLoading(false)
},3000)
}
return(
<View style={ styles.container }>
<View style={styles.findRecipe}>
<ScrollView>
<Text style={ styles.title }> البروتينات - اللحوم </Text>
<View>
<View style={styles.switchView}>
<Text>مكعبات لحمة</Text>
<Switch value={hasMeatCube} onValueChange={newValue=> setHasMeatCube(newValue)} />
</View>
<View style={styles.switchView}>
<Text> لحمة مفرومة </Text>
<Switch value={hasGroundMeat} onValueChange={newValue=> setHasGroundMeat(newValue)} />
</View>
<View style={styles.switchView}>
<Text>كفتة</Text>
<Switch value={hasKofta} onValueChange={newValue=> setHasKofta(newValue)} />
</View>
<View style={styles.switchView}>
<Text>كبدة</Text>
<Switch value={hasLiver} onValueChange={newValue=> setHasLiver(newValue)} />
</View>
<View style={styles.switchView}>
<Text>سجق</Text>
<Switch value={hasSusage} onValueChange={newValue=> setHasSusage(newValue)} />
</View>
<View style={styles.switchView}>
<Text> موزة لحمة </Text>
<Switch value={hasMeatShank} onValueChange={newValue=> setHasMeatShank(newValue)} />
</ScrollView>
<View>
<AnimatedLoader
visible={loading}
overlayColor="rgba(255,255,255,0.75)"
source={require("../../assets/SearchRecipe.json")}
animationStyle={styles.lottie}
speed={1}
/>
<TouchableOpacity
style={styles.submit}
onPress={ startLoading }
>
<Text>يلا</Text>
</TouchableOpacity>
</View>
</View>
</View>
);
};
const styles = StyleSheet.create({
});
export default Switch;
import React from 'react';
import {View, Text, StyleSheet, FlatList} from 'react-native';
import {MEALS} from '../../data/RecipiesData'
const FilteredList = ({navigation, route})=>{
const {filteredList} = route.params
const data = MEALS.filter(meal => {
if(filteredList.hasMeatCube && !meal.hasMeatCube){
return false
}
if(filteredList.hasGroundMeat && !meal.hasGroundMeat){
return false
}
if(filteredList.hasTurkey && !meal.hasTurkey){
return false
}
if(filteredList.hasKofta && !meal.hasKofta){
return false
}
if(filteredList.hasLiver && !meal.hasLiver){
return false
}
if(filteredList.hasSusage && !meal.hasSusage){
return false
}
if(filteredList.hasMeatShank && !meal.hasMeatShank){
return false
}
if(filteredList.hasEscalop && !meal.hasEscalop){
return false
}
if(filteredList.hasCheckin && !meal.hasCheckin){
return false
}
if(filteredList.hasCheckinFillet && !meal.hasCheckinFillet){
return false
}
if(filteredList.hasKidney && !meal.hasKidney){
return false
}
if(filteredList.hasCabbage && !meal.hasCabbage){
return false
}
return true;
this is the model
class Meal {
constructor(
id,
categoryIds,
title,
imageUrl,
flag,
duration,
calories,
servings,
ingredients,
steps,
hasMeatCube,
hasGroundMeat,
hasTurkey,
hasCabbage,
) {
this.id = id;
this.categoryIds = categoryIds;
this.title = title;
this.imageUrl = imageUrl;
this.flag = flag;
this.duration = duration;
this.calories = calories;
this.servings = servings;
this.ingredients = ingredients;
this.steps = steps;
this.hasMeatCube = hasMeatCube;
this.hasGroundMeat = hasGroundMeat;
this.hasTurkey = hasTurkey;
this.hasCabbage = hasCabbage;
}
}
export default Meal;
and this is the MEALS array
import Meal from '../model/Meal';
export const MEALS = [
new Meal('m1',['c1', 'c12'], 'كفتة',
[
'../assets/Egyptian_Kofta.jpg',
'../assets/Egyptian_Kofta2.jpg',
],
'EG',
45,
1250,
4,
[
'1 كيلو لحمة مفرومة',
'1 بصلة مفرومة',
'1 صفار بيضة',
],
[
'وضع اللحمة والملح والفلفل في بولة',
'اضافة صفار البض والاوريجانو',
],
false,true,false,true,false,false,false,false,false,
false,false,false,false,false,false,false,false,false,
),
new Meal('m2',['c9', 'c13'], 'فراخ مشوية بالكرات',
[
'..assets/Grilled_Chicken_Leeks_.jpg',
'..assets/Grilled_Chicken_Leeks_1.jpg',
],
'JP',
25,
4,
750,
[
'نص كيلو افخاد دجاج مخلية بالجلد',
'ملح وفلفل اسود',
'صويا صوص',
],
[
'تقطيخ الفخاد لقطع صغيرة ',
'نتبلها بالملح والفلفل',
'نضيف الصويا على الفراخ',
],
false,false,false,false,false,false,false,false,true,
false,false,false,false,true,false,false,false,false,
),
new Meal('m3', ['c4', 'c13'], 'فراخ تندوري',
[
'../assets/Tandoori_.jpg',
'../assets/Tandoori_1.jpg',
],
'IN',
60,
4,
1200,
[
'فرخة مقطعة منزوعة الجلد',
'ربع كوب عصير ليمون',
'فصين ثوم مفرومين',
],
[
'نقطع الفرخة ارباع ونعمل فتحات بالسكينة علشان تتبل مكويس',
'نحط التوابل والزبادي في الخلاط لغاية ما نعمل منهم معجون',
],
false,false,false,false,false,false,false,false,true,
false,false,false,false,false,false,false,false,false,
),
new Meal('m4',['c5', 'c14'], 'جمبري مشطشط بالكرفس والكاجو',
[
'../assets/Spicy_Shrimp_Celery_.jpg',
'../assets/Spicy_Shrimp_Celery_1.jpg',
],
'CN',
15,
4,
500,
[
'كيلو جمبري مقشر',
'بصل اخضر مقطع',
'معلقة صويا صوص',
'معلقة زيت سمسم',
'معلقة هل ابيض',
],
[
'نخلط الصويا صوص مع الخل وزيت السمسم',
'نضيف الزنجبيل والثزوم والشطة',
'نسخن طاسة تيفال لمدة دقيقتين',
],
false,false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,true,false,
),
];
Solution 1:[1]
Obviously I can't recreate a react environment here. Instead I have built the object route, so I can filter the MEALS array (OP provided in his update) according to the checked switches as defined in route.params.filteredList:
// testing environment:
const route={params:{filteredList:{
hasGroundMeat:1, hasCabbage:1}}};
class Meal {
constructor(id,categoryIds,title,imageUrl,
flag,duration,calories,servings,ingredients,steps,
hasMeatCube,hasGroundMeat,hasTurkey,hasCabbage) {
this.id = id;
this.categoryIds = categoryIds;
this.title = title;
this.imageUrl = imageUrl;
this.flag = flag;
this.duration = duration;
this.calories = calories;
this.servings = servings;
this.ingredients = ingredients;
this.steps = steps;
this.hasMeatCube = hasMeatCube;
this.hasGroundMeat = hasGroundMeat;
this.hasTurkey = hasTurkey;
this.hasCabbage = hasCabbage;}
}
const MEALS=[new Meal('m1',['c1', 'c12'], '????',
[
'../assets/Egyptian_Kofta.jpg',
'../assets/Egyptian_Kofta2.jpg',
],
'EG',
45,
1250,
4,
[
'1 ???? ???? ??????',
'1 ???? ??????',
'1 ???? ????',
],
[
'??? ?????? ?????? ??????? ?? ????',
'????? ???? ???? ???????????',
],
false,true,false,true,false,false,false,false,false,
false,false,false,false,false,false,false,false,false,
),
new Meal('m2',['c9', 'c13'], '???? ????? ???????',
[
'..assets/Grilled_Chicken_Leeks_.jpg',
'..assets/Grilled_Chicken_Leeks_1.jpg',
],
'JP',
25,
4,
750,
[
'?? ???? ????? ???? ????? ??????',
'??? ????? ????',
'???? ???',
],
[
'????? ?????? ???? ????? ',
'?????? ?????? ???????',
'???? ?????? ??? ??????',
],
false,false,false,false,false,false,false,false,true,
false,false,false,false,true,false,false,false,false,
),
new Meal('m3', ['c4', 'c13'], '???? ??????',
[
'../assets/Tandoori_.jpg',
'../assets/Tandoori_1.jpg',
],
'IN',
60,
4,
1200,
[
'???? ????? ?????? ?????',
'??? ??? ???? ?????',
'???? ??? ???????',
],
[
'???? ?????? ????? ????? ????? ???????? ????? ???? ?????',
'??? ??????? ???????? ?? ?????? ????? ?? ???? ???? ?????',
],
false,false,false,false,false,false,false,false,true,
false,false,false,false,false,false,false,false,false,
),
new Meal('m4',['c5', 'c14'], '????? ????? ??????? ???????',
[
'../assets/Spicy_Shrimp_Celery_.jpg',
'../assets/Spicy_Shrimp_Celery_1.jpg',
],
'CN',
15,
4,
500,
[
'???? ????? ????',
'??? ???? ????',
'????? ???? ???',
'????? ??? ????',
'????? ?? ????',
],
[
'???? ?????? ??? ?? ???? ???? ??????',
'???? ???????? ??????? ??????',
'???? ???? ????? ???? ???????',
],
false,false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,true,false,
),
];
// console.log(MEALS);
// actual filtering part for your React environment:
const ingredients="MeatCube,GroundMeat,Turkey,Kofta,Liver,Susage,MeatShank,Escalop,Checkin,CheckinFillet,Kidney,Cabbage".split(",").map(e=>"has"+e)
const fl = route.params.filteredList;
const data = MEALS.filter(meal =>
// ingredients.some(ing=>fl[ing]&&meal[ing])
ingredients.every(ing=>!fl[ing]||meal[ing])
)
console.log(data.map(d=>d.id+": "+d.title).join(","));
The way the MEALS array is created seems overly complicated to me and it is also flawed in a way that only the first four Boolean has...-ingredients arguments are picked up in each new Meal() instantiation call. The remaining 14 Boolean arguments are completely ignored.
Please not that I changed the filtering method too. In the MEALS.filter() callback function you will find two variants:
// ingredients.some(ing=>fl[ing]&&meal[ing])
ingredients.every(ing=>!fl[ing]||meal[ing])
The first one (commented out) requires at least one ingredient of filteredList to be in a meal while the second one requires all of the selected ingredients to be in it.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |

