我有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并且已经有了这些变量。您可以简单地使用filtersListselectedFilters而不是分别使用tempFilterstempSelected
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;就足够添加到结尾了。

07-24 09:17