【问题标题】:Vue/Javascript - Sort array of objects based on its existence in another arrayVue/Javascript - 根据对象在另一个数组中的存在对对象数组进行排序
【发布时间】:2021-02-01 15:55:17
【问题描述】:

我有两个数组,array1 包含所有对象,array2 包含基于搜索字符串过滤的对象。

目前我正在向用户呈现 array2(当搜索字符串为空时,它将包含来自 array1 的所有对象,但如果搜索字符串不为空,则仅返回过滤的对象)但我想显示所有对象和样式过滤的对象(与搜索匹配的对象)不同,并将与搜索查询匹配的对象保留在数组/列表的顶部,如果除此之外,我还可以按字母顺序对匹配的对象进行排序。

这是我根据搜索查询进行过滤的方式:

export default {
    name: "RegionSelector",
  
    data: () => ({
      searchRegionTextValue: "",
  
      regions: [
        {
          country: "USA",
          flag: "flag-en-us",
          name: "United States",
          language: "English",
        },
        {
          country: "UK",
          flag: "flag-en-gb",
          name: "United Kingdom",
          language: "English",
        },
        {
          country: "DE",
          flag: "flag-de",
          name: "Germany",
          language: " German",
        },
      ],
    }),
  
    methods: {
      // Used in my v-for in the template to style non-matched results differently
      checkRegion(region) {
        var isInArray =
          this.filteredRegions.find(function(el) {
            return el === region;
          }) !== undefined;
        return isInArray;
      },
  
    computed: {
      filteredRegions() {
        function compare(a, b) {
          if (a.name < b.name) return -1;
          if (a.name > b.name) return 1;
  
          return 0;
        }
  
        let regions = this.regions.filter((region) => {
          return (
            region.name
              .toLowerCase()
              .indexOf(this.searchRegionTextValue.toLowerCase()) != -1 ||
            region.language
              .toLowerCase()
              .indexOf(this.searchRegionTextValue.toLowerCase()) != -1
          );
        });
  
        regions.sort(compare);
  
        return regions;
      },
    },
};

在我的模板中,我以这种方式渲染它们(显示所有对象,但样式不同):

<div v-for="region in regions">
    <span
    :class="checkRegion(region) ? 'matched-query' : 'unmatched-query'">
        {{region.name}}
    </span>
</div>

如何实现上述排序?

【问题讨论】:

  • 您的问题(和问题空间)不是关于 Vue 渲染,而是更多关于数据结构操作。请考虑完全删除对 Vue 的任何提及(您清楚地知道如何呈现列表)并提供起始对象/列表以及生成的数据结构的外观。这样一来,重点就放在了真正的问题上,而不是 Vue 渲染上。

标签: javascript arrays sorting object vuejs2


【解决方案1】:

使用扩展运算符将原始数组附加到过滤数组的结果,如下所示

[...filteredRegions(), ...regions]

这会将匹配项添加到数组的开头,接下来我们从数组中删除重复项,我们可以通过将new Set() 包裹在它周围来做到这一点,就像这样

const newRegions = new Set([...filteredRegions(), ...regions])

您可以像这样将其转换为普通数组。

const newRegions = [...new Set([...filteredRegions(), ...regions])]

参见下面的示例代码:

const regions = [
  {
    country: "USA",
    flag: "flag-en-us",
    name: "United States",
    language: "English",
  },
  {
    country: "UK",
    flag: "flag-en-gb",
    name: "United Kingdom",
    language: "English",
  },
  {
    country: "DE",
    flag: "flag-de",
    name: "Germany",
    language: " German",
  },
  {
    country: "NG",
    flag: "flag-ng",
    name: "Nigeria",
    language: "English",
  },
]

function compare(a, b) {
  if (a.name < b.name) return -1;
  if (a.name > b.name) return 1;

  return 0;
}

function filteredRegions(query = 'Nigeria') {
  let regions = regions.filter((region) => {
    return (
      region.name
        .toLowerCase()
        .indexOf(query.toLowerCase()) != -1 || region.language
        .toLowerCase()
        .indexOf(query.toLowerCase()) != -1
    );
  });

  regions.sort(compare);

  return regions;
}

let result = [...new Set([...filteredRegions(), ...regions])]

【讨论】:

    【解决方案2】:

    您可以引入第二个 computed 方法,其中包含不匹配的对象,并为该数组执行另一个 for loop

    或者

    “可能”更有效,引入另一个属性将对象标记为匹配对象,并将该属性用于排序逻辑

    computed: {
      newregions() {
        function compare(a, b) {
          if (a.matched && !b.matched) return -1;
          if (!a.matched && b.matched) return 1;
          if (a.matched && b.matched) {
            if (a.name < b.name) return -1;
            if (a.name > b.name) return 1;
          }
    
          return 0;
        }
    
        let regions = this.regions.map((region) => ({
          ...region,
          matched: region.name
              .toLowerCase()
              .indexOf(this.searchRegionTextValue.toLowerCase()) != -1 ||
            region.language
              .toLowerCase()
              .indexOf(this.searchRegionTextValue.toLowerCase()) != -1
        }));
    
        regions.sort(compare);
    
        return regions;
      },
    },
    

    然后在你的模板上

    <div v-for="region in newregions">
        <span
        :class="region.matched ? 'matched-query' : 'unmatched-query'">
            {{region.name}}
        </span>
    </div>
    

    【讨论】:

      猜你喜欢
      • 2021-11-20
      • 1970-01-01
      • 1970-01-01
      • 2016-06-02
      • 1970-01-01
      • 1970-01-01
      • 2019-03-28
      相关资源
      最近更新 更多