我有4个下拉多选过滤器在一行。
它需要渲染和在每个选定的选项上。
我需要在新数组中添加选中的选项并更新当前数组->object.property.selected=false/true。
我正在搜索对象数组,每个对象的一个属性都有对象数组。
您可以在此代码笔上找到代码示例:https://codepen.io/nikolatrajkovicits/pen/JqpWOX?editors=0012
下面是该数组的外观:
export const getFiltersList = () => [
{
title: 'Taxonomy',
options: [
{
id: 0,
name: 'Competitions',
selected: false,
key: 'Taxonomy'
},
{
id: 1,
name: 'Events',
selected: false,
key: 'Taxonomy'
},
{
id: 2,
name: 'Data',
selected: false,
key: 'Taxonomy'
},
{
id: 3,
name: 'Organisations',
selected: false,
key: 'Taxonomy'
},
{
id: 4,
name: 'Players',
selected: false,
key: 'Taxonomy'
},
{
id: 5,
name: 'Teams',
selected: false,
key: 'Taxonomy'
}
]
},
{
title: 'Source',
options: [
{
id: 0,
name: 'Facebook',
selected: false,
key: 'Source'
},
{
id: 1,
name: 'Twitter',
selected: false,
key: 'Source'
},
{
id: 2,
name: 'Instagram',
selected: false,
key: 'Source'
},
{
id: 3,
name: 'Websites',
selected: false,
key: 'Source'
}
]
},
{
title: 'Timeframe',
options: [
{
id: 0,
name: 'Past hour',
selected: false,
key: 'Timeframe'
},
{
id: 1,
name: 'Past 24 hours',
selected: false,
key: 'Timeframe'
},
{
id: 2,
name: 'Past week',
selected: false,
key: 'Timeframe'
},
{
id: 3,
name: 'Past month',
selected: false,
key: 'Timeframe'
},
{
id: 4,
name: 'Past year',
selected: false,
key: 'Timeframe'
}
]
},
{
title: 'Location',
options: [
{
id: 0,
name: 'Location 1',
selected: false,
key: 'Location'
},
{
id: 1,
name: 'Location 2',
selected: false,
key: 'Location'
},
{
id: 2,
name: 'Location 3',
selected: false,
key: 'Location'
},
{
id: 3,
name: 'Location 4',
selected: false,
key: 'Location'
}
]
}
];
以下是算法:
selectFilter = ({ id, key }) => {
const { filtersList, selectedFilters } = this.state;
const tempFilters = filtersList;
const tempSelected = selectedFilters;
const i = tempSelected.length;
tempFilters.forEach((filter) => {
if (filter.title === key) {
filter.options.forEach((option) => {
if (option.id === id) {
option.selected = !option.selected;
const isFilterExist = tempSelected.filter(
(selectedFilter) => selectedFilter.name === option.name
);
if (!isFilterExist.length) {
const selectedItem = { name: option.name, key, id };
tempSelected[i] = selectedItem;
}
}
});
}
});
this.setState({
filtersList: tempFilters,
selectedFilters: tempSelected
});
};
在代码笔上可以找到纯javascript代码的版本。
如何使更好更干净更快的搜索算法?
有什么建议文章,教程,评论吗?
最佳答案
首先,这两项是不必要的:
const tempFilters = filtersList;
const tempSelected = selectedFilters;
变量are references to the exact same objects并且已经有了这些变量。您可以简单地使用
filtersList
和selectedFilters
而不是分别使用tempFilters
和tempSelected
。tempFilters.forEach((filter) => {
if (filter.title === key) {`
由于
.forEach
的全部是if
,因此这表明您需要改用.filter
。tempFilters.filter((filter) => filter.title === key)`
同样,当你进入
if
filter.options.forEach((option) => {
if (option.id === id) {
你可以简化为
filter.options.filter((option) => option.id === id)
继续下去,这条线是浪费
const isFilterExist = tempSelected.filter(
(selectedFilter) => selectedFilter.name === option.name
);
不需要对整个数组运行
.filter
,因为您只关心是否有与谓词匹配的项。改为使用.some
,它直接为您提供一个布尔值:const isFilterExist = tempSelected.some(
(selectedFilter) => selectedFilter.name === option.name
);
而且,因为你总是颠倒布尔,所以如果找到一个过滤器就不那么简单了——如果一个过滤器不存在,那么反转谓词并使用
.every
来得到它。原因是某些元素匹配,但您需要相反的元素,即逻辑上每个元素都匹配谓词的完全相反的元素。最后,我将名称改为使用has
听起来更自然一些。const hasNoFilter = tempSelected.every(
(selectedFilter) => selectedFilter.name !== option.name
);
因此,首先,可以将代码重新写入以下内容:
selectFilter = ({ id, key }) => {
const { filtersList, selectedFilters } = this.state;
const i = selectedFilters.length;
filtersList
.filter((filter) => filter.title === key)
.forEach(filter => {
filter.options
.filter((option) => option.id === id)
.forEach(option => {
option.selected = !option.selected;
const hasNoFilter = tempSelected.every(
(selectedFilter) => selectedFilter.name !== option.name
);
if (hasNoFilter) {
const selectedItem = { name: option.name, key, id };
selectedFilters[i] = selectedItem;
}
});
});
this.setState({
filtersList,
selectedFilters
});
};
这使我们更容易对代码进行推理。
似乎您有具有唯一标题的筛选器,以及其中具有唯一id的选项,这意味着title+id的组合也将是唯一的。
考虑到这一点,您只对一个值感兴趣,而不是对任何数量的值感兴趣,因此不需要执行所有循环您可以使用
.find
获取感兴趣的值,从而使整个代码更易于阅读:selectFilter = ({ id, key }) => {
const { filtersList, selectedFilters } = this.state;
const filter = filtersList.find((filter) => filter.title === key);
const option = filter.options.find((option) => option.id === id)
option.selected = !option.selected;
const hasNoFilter = tempSelected.every(
(selectedFilter) => selectedFilter.name !== option.name
);
if (hasNoFilter) {
const selectedItem = { name: option.name, key, id };
selectedFilters.push(selectedItem);
}
this.setState({
filtersList,
selectedFilters
});
};
}
由于此代码只处理单个项,因此不需要
const i = selectedFilters.length;
因为要在数组中进行一次插入。以前,包含在all-the循环中的行建议您插入多个值,但所有值都在同一位置,以便只保留最后一个值。一个简单的selectedFilters[i] = selectedItem;
就足够添加到结尾了。