【问题标题】:Transform an array of key/value pairs into array of objects将键/值对数组转换为对象数组
【发布时间】:2021-02-14 13:15:54
【问题描述】:

我需要能够将数组转换为包含多个对象的新数组。例如,如果我有这个数组:

["name", "Tom", "id", "48688", "name", "Bob", "id", "91282"]

我希望能够将其转换为:

[{
   "name": "Tom",
   "id": "48688"
}, {
   "name": "Bob"
   "id": "91282"
}]

【问题讨论】:

  • 一开始你是怎么得到它的?从一开始,这应该是一个对象数组。
  • 这是一个我自己回答的问题,并将我的答案作为一个社区 wiki。这个问题实际上只是一个例子。
  • 如果你有一个对象的三个属性怎么办?你需要提前知道吗?为什么?

标签: javascript arrays object


【解决方案1】:

zip 函数采用键 k 和值 v 并用它们创建对象是很常见的:

const zip =
  (k, v) =>
    ({[k]: v});

zip("name", "Tom");
//=> {name: "Tom"}

如果键和值都在一个数组中,您可以像zip(...arr) 那样在一个 zip 调用中传播它。或者你可以稍微修改一下签名:

const zip =
  ([k, v]) =>
    ({[k]: v});

zip(["name", "Tom"]);
//=> {name: "Tom"}

如果数组包含多对键值对,那么我们可以设计一个递归版本的zip

const Nil = Symbol();

const zip =
  ([k = Nil, v = Nil, ...xs], o = {}) =>
    k === Nil && v === Nil
      ? o
      : zip(xs, (o[k] = v, o));
      
zip(["name", "Tom", "id", "48688"]);
//=> {name: "Tom", id: "48688"}

我们现在可以考虑将您的数组分割成相等数量的对块并将zip 应用于每个块。

首先让我们编写一个 slices 函数,它将一个数组切割成 n 个元素的切片:

const slices =
  (xs, n, ys = []) =>
    xs.length === 0
      ? ys
      : slices(xs.slice(n), n, (ys.push(xs.slice(0, n)), ys));

slices(["name", "Tom", "id", "48688", "name", "Bob", "id", "91282"], 4);
//=> [["name", "Tom", "id", "48688"],["name", "Bob", "id", "91282"]]

我们现在可以将zip 应用于每个块:

slices(["name", "Tom", "id", "48688", "name", "Bob", "id", "91282"], 4)
  .map(chunk => zip(chunk));
//=> [{name: "Tom", id: "48688"},{name: "Bob", id: "91282"}]

const Nil = Symbol();

const zip =
  ([k = Nil, v = Nil, ...xs], o = {}) =>
    k === Nil && v === Nil
      ? o
      : zip(xs, (o[k] = v, o));

const slices =
  (xs, n, ys = []) =>
    xs.length === 0
      ? ys
      : slices(xs.slice(n), n, (ys.push(xs.slice(0, n)), ys));

console.log(

  slices(["name", "Tom", "id", "48688", "name", "Bob", "id", "91282"], 4)
    .map(chunk => zip(chunk))
  
);

【讨论】:

    【解决方案2】:

    使用for 循环将其迭代增加4,如下所示:

    let results = [];
    for(let i = 0; i < array.length; i += 4) {    // increment i by 4 to get to the start of the next object data
      results.push({
        id: array[i + 3],                         // array[i + 0] is the string "name", array[i + 1] is the name,
        name: array[i + 1]                        // array[i + 2] is the string "id" and array[i + 3] is the id
      });
    }
    

    演示:

    let array = ["name", "Tom", "id", "48688", "name", "Bob", "id", "91282", "name", "Ibrahim", "id", "7"];
    
    let results = [];
    for(let i = 0; i < array.length; i += 4) {
      results.push({
        id: array[i + 3],
        name: array[i + 1]
      });
    }
    
    console.log(results);

    【讨论】:

      【解决方案3】:

      我经常看到这样的问题,所以我做了一个小转换器来实现这个特定的目标:

      // input
      var inputArray = ["name", "Tom", "id", "48688", "name", "Bob", "id", "91282"]
      var sizeOfObjects = 2; // amount of entries per object
      // function
      function convert(array, size) {
          var newArray = [] //set up an array
          var res3 = array.reduce((acc, item, index) => {
              if (index % 2 == 0) { // if the index is even:
                  acc[`${item}`] = array[index+1]; // add entry to array
              }
              if (Object.keys(acc).length == size) { // if the desired size has been reached: 
                  newArray.push(acc); // push the object into the array
                  acc = {}; // reset the object
              }
              return acc; // preserve accumulator so it doesn't get forgotten
          }, {}); // initial value of reducer is an empty object
        return newArray; //return the array
      }
      console.log(convert(inputArray, sizeOfObjects));

      希望这对正在寻找此类问题的答案的人们有所帮助。

      如果您只想创建一个对象,请查看其他问题/答案:Create object from array

      【讨论】:

        【解决方案4】:

        我们可以使用% 运算符来决定是否找到要插入数组的对象:

        const data = ["name", "Tom", "id", "48688", "name", "Bob", "id", "91282"];
        
        makeObjectArray = arr => {
          const result = [], temp = [];
          arr.forEach((a, i)=>{
              if (i % 2 == 0)
                temp.push({ [arr[i]]: arr[i + 1]})
              if (i % 3 == 0 && i != 0) {
                result.push(Object.assign({}, ...temp));
                temp.length = 0;
              }
          })
          return result;
        }
        
        console.log(makeObjectArray(data))

        【讨论】:

          【解决方案5】:

          您可以使用以下辅助函数将数组分成所需大小的较小块:

          function chunk(to_chunk, chunk_size) {
              var output = [];
              if(to_chunk.length > chunk_size) {
                  output.push(to_chunk.slice(0, chunk_size));
                  output.push(chunk(to_chunk.slice(chunk_size)));
                  return output;
              } else {
                  return to_chunk;
              }
          }
          

          然后您可以将结果与其他函数映射以返回您想要的对象:

          var final = chunk(seed, 4).map((x) => myObject(x));
          function myObject(seed) {
              var output = {};
              output[seed[0]] = seed[1];
              output[seed[2]] = seed[3];
              return output;
          }
          

          我认为这种方法在可读性方面很好,把你所有的放在一起:

          var seed = ["name", "Tom", "id", "48688", "name", "Bob", "id", "91282"];
          var final = chunk(seed, 4).map((x) => myObject(x));
          console.log(final);
          function chunk(to_chunk, chunk_size)
          {
              var output = [];
              if(to_chunk.length > chunk_size) {
                  output.push(to_chunk.slice(0, chunk_size));
                  output.push(chunk(to_chunk.slice(chunk_size)));
                  return output;
              } else {
                  return to_chunk;
              }
          }
          
          function myObject(seed)
          {
              var output = {};
              output[seed[0]] = seed[1];
              output[seed[2]] = seed[3];
              return output;
          }

          【讨论】:

            【解决方案6】:

            您可以采用动态方法,使用对象跟踪相同命名键的目标索引。

            const
                getArray = data => {
                    let indices = {},
                        result = [],
                        i = 0;
            
                    while (i < data.length) {
                        const [key, value] = data.slice(i, i += 2);
                        indices[key] ??= 0;
                        (result[indices[key]++] ??= {})[key] = value;
                    }
                    return result;
                },
                data1 = ["name", "Tom", "id", "48688", "name", "Bob", "id", "91282"],
                data2 = ["name", "Tom", "id", "48688", "color", "green", "name", "Bob", "id", "91282", "color", "red"];
            
            console.log(getArray(data1));
            console.log(getArray(data2));
            .as-console-wrapper { max-height: 100% !important; top: 0; }

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-08-25
              • 2019-01-14
              • 1970-01-01
              • 2018-05-10
              相关资源
              最近更新 更多