javascript根据另一个更大的数组创建具有固定长度的对象数组

时间:2018-08-06 20:51:12

标签: javascript arrays ecmascript-6

给出一个长度相等的数组:

const items = [
  'this/is/path1',
  'this/is/path2',
  'this/is/path3',
  'this/is/path4',
  'this/is/path5',
  'this/is/path6'
];

我想创建一个对象数组,该数组的长度为objnb。 基于此长度,我将上面的items分成多个块,然后将第一个索引存储在新的对象属性path上,并将以下元素存储在other1,{{1} };其他对象块也一样。

我的解决方案很hacky:

other2

输出正确:

const objnb = 2;
const other1 = true;
const other2 = true;
const outputobjs = items.length / objnb;
const result = items.map((entry, index) => {
  let obj = {};
  console.log({ entry, index })
  if (index % outputobjs === 0) {
    obj.path = entry;
    obj.others = {};
    if (other1) {
      obj.others.two = items[index + 1];
    }
    if (other2) {
      obj.others.three = items[index + 2];
    }

    return obj;
  }

  return obj;
})


console.log('result: ', result)

但是不幸的是,我得到了我不想要的空对象。 如何以更简洁的方式实现相同目标?

首选结果将不包含空对象。

更新

另一个示例是:

[ { path: 'this/is/path1',
    others: { two: 'this/is/path2', three: 'this/is/path3' } },
  {},
  {},
  { path: 'this/is/path4',
    others: { two: 'this/is/path5', three: 'this/is/path6' } },
  {},
  {} ]

结果是:

const items = [
  'this/is/path1',
  'this/is/path2',
  'this/is/path3',
  'this/is/path4'
];

const objnb = 2;
const other1 = true;
const other2 = false;
const outputobjs = items.length / objnb;
const result = items.map((entry, index) => {
  let obj = {};
  console.log({ entry, index })
  if (index % outputobjs === 0) {
    obj.path = entry;
    obj.others = {};
    if (other1) {
      obj.others.two = items[index + 1];
    }
    if (other2) {
      obj.others.three = items[index + 2];
    }

    return obj;
  }

  return obj;
})


console.log('result: ', result)

说明:

新数组中的每个对象都将相似,例如,它们都将具有[ { path: 'this/is/path1', others: { two: 'this/is/path2' } }, {}, { path: 'this/is/path3', others: { two: 'this/is/path4' } }, {} ] ,并且由于我们将原始数组均匀划分,因此新对象将具有所有相同的属性。例如,如果一个对象具有path,则新数组中的其余对象都将具有此属性,如果应该具有two,则它们都将具有该属性。

新对象将如下所示:

three

因此,基本上,通过将原始项数组划分为特定的数(2、3、4等),我们会将其分块为较小的数组,新对象{ path: 'this/is/path1', others: { two: 'this/is/path2', three: 'this/is/path3' // optional; if one object has this, others must have it too. } } 将是{{1 }},并且如果此新的分块数组中还有一个项目,则path将是chunkedArray[0],如果还有一个项目,则two将是chunkedArray[1]

因此,如果我们将其除以2,那么我们将得到:

three

因此,新对象将具有chunkedArray[2]const chunkedArray1 = [ 'this/is/path1', // path 'this/is/path2', //others.two 'this/is/path3' //others.three ]; const chunkedArray2 = [ 'this/is/path4',// path 'this/is/path5',//others.two 'this/is/path6'//others.three ];

但是如果将其分为3,我们将得到:

two

所以每个对象只有路径和three

每个新的chunkedArray的长度至少为2,这意味着路径和const chunkedArray1 = [ 'this/is/path1',// path 'this/is/path2'//others.two ]; const chunkedArray2 = [ 'this/is/path3',// path 'this/is/path4'//others.two ]; const chunkedArray3 = [ 'this/is/path5',// path 'this/is/path6'//others.two ]; 存在于每个新对象中。

另一个例子:

一个基本的例子是,如果原始数组是三个,那么我们就不能将其均匀地分成较小的块,所以:

two

如果原始数组为两个长度,则在此处相同:

two

3 个答案:

答案 0 :(得分:1)

以下是使用reduce的一种解决方案。

const items = [
  'this/is/path1',
  'this/is/path2',
  'this/is/path3',
  'this/is/path4',
  'this/is/path5',
  'this/is/path6'
]

function splitItems(data, chunkSize) {
  if (chunkSize < 2) return data // or the special value you'd like.
  const labels = {
    1: 'one',
    2: 'two',
    3: 'three',
    4: 'four'
    // ... others
  }
  return data.reduce((pre, cur, index) => {
    if (index % chunkSize === 0) {
      /* for old question
      pre.push({
        path: cur,
        others: {}
      })*/
      let newItem = {
        path: cur,
        others: {}
      }
      Array.from(Array(chunkSize-1).keys()).map( itemIndex => {
        newItem.others[labels[(itemIndex+1) % chunkSize + 1]] = '' //or other default valu
      })
      pre.push(newItem)
    }
    else {
      pre[pre.length - 1].others[labels[index % chunkSize + 1]] = items[index]
    }
    return pre
  }, [])
}

console.log('@Test Case 1@', splitItems(items, 2), '@@')
console.log('@Test Case 2@', splitItems(items.slice(0, 2), 2), '@@')
console.log('@Test Case 3@', splitItems(items.slice(0, 4), 2), '@@')
console.log('@Test Case 4@', splitItems(items.slice(0, 5), 3), '@@')

// calc the size first, then exec splitItems
function splitByLength(data, numberOfChunks) {
  let chunkSize = Math.round(data.length/3, 0)
  return splitItems(data, chunkSize)
}
console.log('@Test Case 5@', splitByLength(items.slice(0, 5), 3), '@@')

答案 1 :(得分:0)

简而言之,您可以循环每3个项目并将其作为对象推送。

const items = [
  'this/is/path1',
  'this/is/path2',
  'this/is/path3',
  'this/is/path4',
  'this/is/path5',
  'this/is/path6'
];
var result = [];
for(var i = 0; i < items.length; i++){
    if(i%3==0){
      result.push({
          path: items[i],
          others: {two: items[i+1] || null, three: items[i+2] || null}
      })
    }
}

console.log(result)

答案 2 :(得分:0)

另一种使用reduce的解决方案,尽管与@sphinx答案有点相似:

const objnb = 3;
const otherKeys = ['two', 'three'];

const items = [
  'this/is/path1',
  'this/is/path2',
  'this/is/path3',
  'this/is/path4',
  'this/is/path5',
  'this/is/path6'
];

const outputobjs = Math.ceil(items.length / objnb);

const ar = items.reduce((memo, item, index) => {
  const mod = index % outputobjs
  if(mod === 0)
    memo.push({path: item, others: {}});
  else if(mod <= otherKeys.length)
    Object.assign(memo[memo.length - 1].others, {[otherKeys[mod -1]]: item});
  return memo;
}, []);

console.log(ar);