【问题标题】:Chaining .filter() into a function to load local JSON data将 .filter() 链接到函数中以加载本地 JSON 数据
【发布时间】:2026-01-26 18:20:06
【问题描述】:

我正在渲染本地 JSON 数据(“类别”),并且正在显示重复的数据。我正在尝试将.filter() 与其他两种方法(.sort().map())一起使用,但我无法删除重复项。我的代码中有什么东西看起来不对吗?

JS sn-p:

var testjson = {
  "d": {
    "results": [{
      "Title": "Aardvark",
      "Category": "Animals",
      "Description": "My Test description",
      "TopTrainingCourse": false,
      "ID": 1,
      "Modified": "2019-03-05T20:13:46Z",
      "Created": "2019-03-05T20:13:36Z"
    }, {
      "Title": "Red Panda",
      "Category": "Animals",
      "Description": "Donec id dictum sem",
      "TopTrainingCourse": true,
      "ID": 10,
      "Modified": "2019-03-06T21:08:25Z",
      "Created": "2019-03-06T21:08:25Z"
    }, {
      "Title": "Tennis",
      "Category": "Sports",
      "Description": "Mauris sagittis ligula",
      "TopTrainingCourse": true,
      "ID": 11,
      "Modified": "2019-03-06T21:08:35Z",
      "Created": "2019-03-06T21:08:35Z"
    }]
  }
}

 loadAllCourses() {
   let jsonRes = testjson.d.results
     .filter((elem, index, self) => {
        return (index === self.indexOf(elem));
     })
     .sort(function(a,b) { // sorts alphabetically
        return (a.Category > b.Category) ? 1 : ((b.Category > a.Category) ? -1 : 0)
     })
     .map(x => {
        return {
          "Category": x.Category,
          "Title": x.Title
        }
     });

    let curIndex = 0;
    $.each(jsonRes, function(idx, val) {

    $(".form-control").append("<option><div data-toggle=\"modal\" data-target=\"#modal-id\">" + val.Category + "</div></option>") // dropdown

【问题讨论】:

  • 我不明白这些问题 - 为什么.filter 应该被链接或不链接 - 根据what.filter 如何影响 .map 使其过时?
  • 您是否复制并粘贴了此脚本?数组中的第三个对象缺少它的开始大括号。另外,我会检查self 的值。我很确定它默认为window
  • @Kramb 此代码示例中缺少大括号,但我的代码中没有。我现在就修复它
  • @VLAZ 我的问题很不清楚,所以我在我的问题正文中澄清了一些事情。基本上我无法删除重复的类别,我想知道问题是否是由链接 .filter().sort() 引起的。
  • @Kramb self 是数组 - 它作为第三个参数传入.filter 回调。而且我不认为它曾经是 windows - this 的值 可以windowself 不会自动分配 - 它只是经常用于捕获 @987654338 的值@ 到正确的上下文。

标签: javascript jquery json filter


【解决方案1】:

在您的代码中,过滤器未按预期工作。 要使其按您的意愿工作,请将其更改为:

.filter((elem, index, self) => {
  return (index === self.map(el => el.Category).indexOf(elem.Category));
})

【讨论】:

  • 成功了,谢谢!我没想到会在那里第二次包含.map()
【解决方案2】:

最简单的解决方案是使用 map 提取 Category prop。查看下面的代码。

还有另一种方法可以使用 ES6 Set 从数组中删除重复项,例如 uniq = [...new Set(array)]

var testjson = {
  "d": {
    "results": [{
      "Title": "Aardvark",
      "Category": "Animals",
      "Description": "My Test description",
      "TopTrainingCourse": false,
      "ID": 1,
      "Modified": "2019-03-05T20:13:46Z",
      "Created": "2019-03-05T20:13:36Z"
    }, {
      "Title": "Red Panda",
      "Category": "Animals",
      "Description": "Donec id dictum sem",
      "TopTrainingCourse": true,
      "ID": 10,
      "Modified": "2019-03-06T21:08:25Z",
      "Created": "2019-03-06T21:08:25Z"
    }, {
      "Title": "Tennis",
      "Category": "Sports",
      "Description": "Mauris sagittis ligula",
      "TopTrainingCourse": true,
      "ID": 11,
      "Modified": "2019-03-06T21:08:35Z",
      "Created": "2019-03-06T21:08:35Z"
    }]
  }
}

const res = testjson.d.results
  .map((obj) => obj.Category)
  .filter((elem, index, self) => index === self.indexOf(elem))
  .sort((a, b) => a - b)

console.log(res)

【讨论】:

    【解决方案3】:

    answer of undefined(虽然简单)循环超出了必要。

    • 答案在filter 列表中循环。 (1 次完整迭代)
    • 对于每个列表项,列表都映射到类别。 (完全迭代等于列表中的项目数量)
    • 然后使用indexOf 在映射值中搜索特定值。 (部分迭代等于列表中的项目数量)

    使用您的示例数据(3 个元素),您最终会迭代同一个列表 1 + 3 + 3 * 0.5 = 5.5 次。 (对indexOf 使用平均 0.5 次迭代)。让我为你增加名单的规模。假设您有一个包含 10 个项目的列表。现在您正在迭代列表 1 + 10 + 10 * 0.5 = 16 次。这可以通过事先制作类别图并每次都参考同一个列表来减少。

    var testjson = { "d": { "results": [{ "Title": "Aardvark", "Category": "Animals", "Description": "My Test description", "TopTrainingCourse": false, "ID": 1, "Modified": "2019-03-05T20:13:46Z", "Created": "2019-03-05T20:13:36Z" }, { "Title": "Red Panda", "Category": "Animals", "Description": "Donec id dictum sem", "TopTrainingCourse": true, "ID": 10, "Modified": "2019-03-06T21:08:25Z", "Created": "2019-03-06T21:08:25Z" }, { "Title": "Tennis", "Category": "Sports", "Description": "Mauris sagittis ligula", "TopTrainingCourse": true, "ID": 11, "Modified": "2019-03-06T21:08:35Z", "Created": "2019-03-06T21:08:35Z" }] } }
    
    console.log(
      testjson.d.results
        .filter(
          function (elem, index) { return index === this.indexOf(elem.Category) },
          testjson.d.results.map(el => el.Category) // <= executes only once
        )
    );

    使用上面的代码将迭代减少到 1 + 1 + 10 * 0.5 = 7 次(对于 10 个列表)。

    不过,这可以通过使用查找对象更快地完成。

    var testjson = { "d": { "results": [{ "Title": "Aardvark", "Category": "Animals", "Description": "My Test description", "TopTrainingCourse": false, "ID": 1, "Modified": "2019-03-05T20:13:46Z", "Created": "2019-03-05T20:13:36Z" }, { "Title": "Red Panda", "Category": "Animals", "Description": "Donec id dictum sem", "TopTrainingCourse": true, "ID": 10, "Modified": "2019-03-06T21:08:25Z", "Created": "2019-03-06T21:08:25Z" }, { "Title": "Tennis", "Category": "Sports", "Description": "Mauris sagittis ligula", "TopTrainingCourse": true, "ID": 11, "Modified": "2019-03-06T21:08:35Z", "Created": "2019-03-06T21:08:35Z" }] } }
    
    console.log(
      testjson.d.results
        .filter(function (elem) {
          return !this[elem.Category] && (this[elem.Category] = true);
        }, {})
    );

    上面只循环了数组本身一次,然后使用查找对象来存储和检查数组中其他元素的存在。这将迭代减少到 1 次。请记住,上述方法确实使用了纯 JavaScript 对象。这意味着类别不能包含保留属性,例如constructor。如果这是一个问题,您可以在检查期间为您的类别添加前缀或后缀。这是一个例子:

    !this['_!!_' + elem.Category] && (this['_!!_' + elem.Category] = true)
    

    请注意,function 关键字的上述用法是有意的。 Arrow function don't have their own this binding,因此不能与filter 方法中的第二个参数结合使用。

    【讨论】: