【问题标题】:Map object values to keys - Javascript将对象值映射到键 - Javascript
【发布时间】:2018-10-30 19:46:51
【问题描述】:

我有一个来自 API 调用的数组。

var response = {
  "data": {
    "data": [{
      "1": "Arun",
      "index": "name"
    }, {
      "1": 70.78,
      "index": "score"
    }]
  }
}

我连接到许多其他 API,它们返回了类似的响应,但密钥发生了变化。有时可能是

var response = {
  "data": {
    "data": [{
      "values": "Harry",
      "index": "name"
    }, {
      "values": 45,
      "index": "score"
    }]
  }
}

var response = {
  "data": {
    "data": [{
      "4": "Richard",
      "index": "name"
    }, {
      "4": 98,
      "index": "score"
    }]
  }
}

我想要一个这样的数组。

[
  {
    name: 'Arun',
    score: 70.78
  }
]

这就是我所做的。

var response = {
  "data": {
    "data": [{
      "1": "Arun",
      "index": "name"
    }, {
      "1": 70.78,
      "index": "score"
    }]
  }
}

const result = [];

const mappedData = _.map(response.data.data, (item) => {
  return {
    [item.index]: item[1]
  };
});

const resultObject = _.reduce(mappedData, (result, currentObject) => {
  for (const key in currentObject) {
    if (currentObject.hasOwnProperty(key)) {
      result[key] = currentObject[key];
    }
  }
  return result;
}, {});

result.push(resultObject)


console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

那么除了在 map 函数中硬编码“1”或“values”之外,有没有更通用的方法来获取键并达到相同的结果?

谢谢。

【问题讨论】:

    标签: javascript arrays lodash javascript-objects


    【解决方案1】:

    使用reduce 而不是map,因此您更新的是同一个对象,而不是创建数组。

    由于包含值的属性可能会有所不同,因此我使用循环来查找第一个未命名为 index 的属性,并使用它的值。

    var response = {
      "data": {
        "data": [{
          "1": "Arun",
          "index": "name"
        }, {
          "1": 70.78,
          "index": "score"
        }]
      }
    }
    
    const mappedData = response.data.data.reduce((acc, item) => {
      var value;
      // find the property that isn't named "item"
      for (var i in item) {
        if (i != "index") {
          value = item[i];
          break;
        }
      }
      acc[item.index] = value;
      return acc;
    }, {});
    
    console.log(mappedData)

    这个不需要lodash,内置的reduce函数很好(但_.reduce也可以工作)。

    【讨论】:

    • 谢谢巴马尔。所以在reduce中,我不想使用item[1]。有没有更通用的方法?
    • 您需要消除对acc[item.index] = item[1] 的需求,因为[1] 的号码会根据不同的请求而变化。
    • 如果情况不同,代码应该如何知道属性是什么?
    • 基于密钥的东西?
    • API 会返回这样的数据似乎很奇怪。你确定不通过搜索就无法找出密钥是什么吗?
    【解决方案2】:

    由于您只关心该对象的值并且它只有两个键,因此您可以在 lodash 中使用 reducefromPairs 轻松完成此操作:

    var response = { "data": { "data": [{ "1": "Arun", "index": "name" }, { "1": 70.78, "index": "score" }] } }
    
    const rv = (o) => _.reverse(_.values(o))
    const r = _.reduce(response.data.data, (a,c) => _.fromPairs([rv(a), rv(c)]))
    
    console.log(r)
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

    转换为 ES6 的相同内容是:

    var response = { "data": { "data": [{ "1": "Arun", "index": "name" }, { "1": 70.78, "index": "score" }] } }
    
    const rv = (o) => Object.values(o).reverse()  // reverse values
    const fp = (arr) => arr.reduce((r, [k,v]) => (r[k] = v, r), {}) // from pairs
    const result = response.data.data.reduce((a,c) => fp([rv(a), rv(c)]))
    
    console.log(result)

    这里的主要思想是首先以数组形式获取对象值,将它们反转以使keyvalue的顺序正确,然后通过from pairsreduce该数组以创建最终对象。

    这种方法的主要优点是我们从不处理对象键,而只关注您真正关心的值。这样,键可以是任何值,但仍然无关紧要。

    【讨论】:

      【解决方案3】:

      您可以尝试删除密钥对 index 并使用结果对象的第一个 value

      const mappedData = _.map(response.data.data, (item) => {
        var tempObj = Object.assign({}, item)
        var index = tempObj.index;
        delete tempObj.index;
        var otherData = Object.values(tempObj)[0];
        return {
          [index]: otherData
        };
      });
      

      【讨论】:

      • 使用item 的副本,这样您就不会删除原始文件并防止以后出现调试问题。如果您不打算使用后者的响应,那么您可以使用item 而不是tempObj
      • 我根本不会再使用原始回复。您提供的代码有效,但数组有 2 个对象,而我需要一个包含一个对象和两个键的数组。
      【解决方案4】:

      刚刚修改了@barmar 方法。我使用Object.keys 从对象中获取密钥。这将删除任何硬编码的依赖项。

      var response = {
        "data": {
          "data": [{
            "1": "Arun",
            "index": "name"
          }, {
            "1": 70.78,
            "index": "score"
          }]
        }
      }
      
      const mappedData = response.data.data.reduce((acc, item,i) => {
        
        var key = Object.keys(item);
        acc[item[key[1]]] =  item[key[0]]
        return acc ;
            
      }, {});
      
      console.log(mappedData)
      <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

      【讨论】:

      • 不保证对象中属性的顺序。您不能确定该值将始终为 key[0] 而不是 key[1]
      • 但如果你愿意承担这个风险,你可以使用Object.values 而不是Object.keys。那你就可以acc[values[1]] = values[0];
      • @Barmar 我会考虑你的建议。正如我在 OP 响应中看到的那样,Object.key 方法对我来说似乎很好。
      • 目前大多数实现都保持顺序,但它可能随时更改,代码将停止工作。
      猜你喜欢
      • 2020-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-23
      • 2012-02-06
      • 1970-01-01
      相关资源
      最近更新 更多