【问题标题】:Filtering an object based on values generated in a for loop in Javascript根据 Javascript 中 for 循环中生成的值过滤对象
【发布时间】:2018-02-04 15:02:45
【问题描述】:

我正在创建一个 Javascript 应用程序(没有第三方框架或库),它需要从 JSON 对象获取位置列表并仅显示给定半径内的这些位置。我已经弄清楚如何确定一个位置的坐标是否在所需的半径内,但我不知道如何使用这些结果过滤对象。以下是相关代码:

function filterObj(obj) {
    var radiusSize = 100;
    return function filter() {
        var result;
        for (var i in obj) {
            var lat = 41.8781;
            var lon = 87.6298;
            var coordinates = (obj[i].location.[0].coordinates).split(",");
            lat2 = Number(coordinates[0]);
            lon2 = Number(coordinates[1]);
            result = toRadius(getDistance(lat, lon, lat2, lon2)) <= radiusSize;
        }
        return result;
    };
}

function getObj() {
    var xml = new XMLHttpRequest();

    xml.onreadystatechange = function() {
        if (xml.readyState === XMLHttpRequest.DONE) {
            if (xml.readyState === 4 && xml.status === 200) {
                obj = JSON.parse(xml.responseText);
                var ObjFilter = filterObj(obj);
                var filtered = obj.filter(objFilter);
                displayLocations(filtered);
            } else {
              //code to handle errors
            }
        }
    };

    xml.open("GET", "/api/locations.json", true);
    xml.send(null);
}

现在,我知道由于 for 循环,filterObj() 反复为“result”返回“false”。我试图将 filterObj() 的结果存储为一个数组,但随后“result”返回了几个包含“toRadius(getDistance())”结果的数组,我再次知道这是因为 for 循环,但是将“结果”赋值移出循环会导致每个结果都为“假”,这是不正确的。

那么,在将对象传递给“displayLocations()”之前,如何使用“toRadius(getDistance())”在“filterObj()”中生成的结果来过滤我在“getObj()”中获取的对象?

这是我正在使用的对象的示例:

[
  {
    "id": 12,
    "name": "Mount Helena City Park",
    "location": [
      {
        "city": "Helena, MT",
        "address": "Mount Helena City Park \nHelena, MT 59601",
        "coordinates": "46.5889179,-112.0593352"
      }
    ]
  }
]

【问题讨论】:

  • 我认为你让这变得比它需要的更难了。请发布您返回的数据的结构,我认为我们将能够帮助使代码以更清洁的方式工作。
  • lat, lon, lat2, lon2 来自哪里?就像你现在的代码一样,它们是未定义的。
  • 如果JSON.parse(xml.responseText) 的值是您所期望的,那么getObj 与此处无关
  • @ChristopherMesser 我不会感到惊讶。我在帖子中添加了我的对象示例。
  • @trincot 很抱歉。我已经编辑了帖子并将它们添加回来。

标签: javascript for-loop filter javascript-objects


【解决方案1】:

您的filterObject 函数(它返回一个过滤器函数)不应将obj 作为参数,因为这违背了这种柯里化函数的目的:obj 将以任何方式逐个元素地传递,到返回的函数,所以这里不需要传递。

而是利用这个机会通过所需的半径。然后返回的函数将使用它。

其次,返回的函数将获取一个元素值作为参数:您需要添加该参数并仅使用该值:那里的整个对象不应该有循环:这是.filter 稍后会做的。

所以它可以像这样工作(为了清楚起见,我重命名了函数):

function nearerThan(radiusSize = 100) {
    return function filter(obj) {
        var lat = 41.8781;
        var lon = 87.6298;
        var coordinates = (obj.location.[0].coordinates).split(",");
        var lat2 = Number(coordinates[0]);
        var lon2 = Number(coordinates[1]);
        var result = toRadius(getDistance(lat, lon, lat2, lon2)) <= radiusSize;
        return result;
    };
}

function getObj() {
    var xml = new XMLHttpRequest();
    var nearerThan100 = nearerThan(100);

    xml.onreadystatechange = function() {
        if (xml.readyState === XMLHttpRequest.DONE) {
            if (xml.readyState === 4 && xml.status === 200) {
                obj = JSON.parse(xml.responseText);
                var filtered = obj.filter(nearerThan100);
                displayLocations(filtered);
            } else {
                //code to handle errors
            }
        }
    };

    xml.open("GET", "/api/locations.json", true);
    xml.send(null);
}

【讨论】:

    【解决方案2】:

    使用承诺并对您的数据结构做出一些假设(生成的 JSON 解析为 [{lat: a, lon: b, ...}, {lat: c, lon: d, ...}, ...],剩下的就是 .filter

    function getFilteredLocations(lat, lon, radius) {
        const distance = item =>
            Math.pow(Math.abs(item.lat - lat), 2)
            + Math.pow(Math.abs(item.lon - lon), 2);
        const r = Math.pow(radius, 2); // rather than doing sqrts in this example
    
        return fetch('/api/locations.json')
            .then(
                response => response.json(),
                error => Promise.reject({message: 'Failed to fetch resource', error}))
            .then(
                arr => arr.filter(item => distance(item) <= r),
                error => Promise.reject({message: 'Failed to parse JSON', error}));
    }
    
    getFilteredLocations(51.5073, -0.12755, 0.009) // ~ 1km radius of Charing Cross, London
        .then(displayLocations)
        .catch(error => console.error(error.message, error.error));
    

    我还为 distance 示例将 GPS 大大简化为毕达哥拉斯,您需要使用您的逻辑将您的 coodinates 属性转换为所需的值

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-03
      • 2023-03-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多