如何优化搜索算法

时间:2019-06-01 10:36:04

标签: javascript arrays reactjs algorithm search

我在行中有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代码的版本。

如何使搜索引擎算法更快更清洁?

有任何建议文章,教程,评论吗?

3 个答案:

答案 0 :(得分:1)

如果我是你,我将在使用Json对象之前更改其结构。例如:如果Json成为键,则为值对,其中键为标题,值为代表选项的数组。这将使您摆脱第一个循环,并像散列表的复杂性一样获得o(1)中的选项列表。 注意:我假设这里的标题是唯一的。 我要进行的第二个更改:您想按ID进行搜索,并且从您提到的示例中,选项数组按ID进行排序,这意味着第一个元素的ID为= 0,并且它的索引为0等。因此,如果新表示形式的值是数组索引i的元素访问也为o(1),这样您也将摆脱第二个循环。 注意:如果标题不是唯一的,或者选项ID没有排序,则需要更新示例以获取更好的解决方案。

答案 1 :(得分:1)

因此,正如您标记的那样,我有一个React实现。

简而言之,我考虑了两个问题(datastate),并将它们从入站数据中分离出来。另外,您输入的数据具有2个不必要的属性(selectedkey)。

key-这是您在return函数期间添加的react实现。我使用了您的标题,因为它在每个对象中都是唯一的。

selected-数据应包含进入应用程序的重要属性,它比数据更能被归类为应用程序状态。如果采用这种方法,则会增加更多的计算开销。选择一个项目时,您必须将所有其他实例更新为false。我将此状态提升到了主应用程序。

这是我写的代码:

dropdown-data.json

[
  {
    "title": "Taxonomy",
    "options": [
      {
        "id": 0,
        "name": "Competitions"
      },
      {
        "id": 1,
        "name": "Events"
      },
      {
        "id": 2,
        "name": "Data"
      },
      {
        "id": 3,
        "name": "Organisations"
      },
      {
        "id": 4,
        "name": "Players"
      },
      {
        "id": 5,
        "name": "Teams"
      }
    ]
  },
  {
    "title": "Source",
    "options": [
      {
        "id": 0,
        "name": "Facebook"
      },
      {
        "id": 1,
        "name": "Twitter"
      },
      {
        "id": 2,
        "name": "Instagram"
      },
      {
        "id": 3,
        "name": "Websites"
      }
    ]
  },
  {
    "title": "Timeframe",
    "options": [
      {
        "id": 0,
        "name": "Past hour"
      },
      {
        "id": 1,
        "name": "Past 24 hours"
      },
      {
        "id": 2,
        "name": "Past week"
      },
      {
        "id": 3,
        "name": "Past month"
      },
      {
        "id": 4,
        "name": "Past year"
      }
    ]
  },
  {
    "title": "Location",
    "options": [
      {
        "id": 0,
        "name": "Location 1"
      },
      {
        "id": 1,
        "name": "Location 2"
      },
      {
        "id": 2,
        "name": "Location 3"
      },
      {
        "id": 3,
        "name": "Location 4"
      }
    ]
  }
]

<App />

import React from "react";

import dropdownData from "./dropdown-data.json";

const Dropdown = ({ options = [], ...props }) => (
  <select {...props}>
    {options.map(({ id, ...option }) => (
      <option key={id}>{option.name}</option>
    ))}
  </select>
);

const App = () => {
  const [data, setData] = React.useState({});

  return (
    <>
      {/* A debugging helper :) */}
      <pre>{JSON.stringify(data, null, 2)}</pre>

      {dropdownData.map(({ title, options }) => (
        <Dropdown
          key={title}
          {...{ options }}
          onChange={({ target }) =>
            setData({
              ...data,
              [title.toLowerCase()]: target.value
            })
          }
        />
      ))}
    </>
  );
};

export default App;

pre标签在下面显示了要返回的数据。由于初始状态有一个空对象,因此您的state不会填充未经修改/不需要的数据。

让我知道这有什么帮助,这是create-react-app中的2个文件。

答案 2 :(得分:1)

首先这两个都是不必要的:

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即可那。推理是元素的 some 匹配,但是您想要相反的选择,这在逻辑上是元素的 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;,因为您将在数组中进行单个插入。以前,所有循环中的行selectedFilters[i] = selectedItem;建议您将多个值插入,但所有值都应放在同一位置,以便仅保留最后一个。一个简单的.push就足以附加到末尾。