JavaScript 数组扁平化:将一个包含对象的数组嵌套多层的数组转换为一维数组

56

我有一个包含多个数组的数组,每个数组中包含多个对象,类似于这样。

[[object1, object2],[object1],[object1,object2,object3]]

这里是被记录到控制台的对象的截图。

将其展平为一个对象数组的最佳方法是什么?

我已经尝试过,但没有成功:

console.log(searchData);  
  var m = [].concat.apply([],searchData);    
console.log(m);

searchData记录了上面截图中的注销信息,但是m没有记录。

下面是searchData的实际内容:

[[{"_id":"55064111d06b96d974937a6f","title":"Generic Title","shortname":"generic-title","contents":"<p>The Healing Center offers practical, social, and spiritual support to individuals and families. Services include, but are not limited to: food and clothing, job skills training and job search assistance, auto repair (Saturdays only), mentoring, financial counseling, tutoring, prayer, life skills training, and helpful information about local community services.</p><p>Stay in touch with us:</p>","__v":0},{"_id":"5508e1405c621d4aad2d2969","title":"test english","shortname":"test-page","contents":"<h2>English Test</h2>","__v":0}],[{"_id":"550b336f33a326aaee84f883","shortname":"ok-url","title":"now english","contents":"<p>okokko</p>","category":"Transportation","__v":0}]]

11
我喜欢 arr.reduce(function(a,b){return a.concat(b);}); 这行代码。 - dandavis
1
由于某种原因,它给了我一个空的 [ ]。我尝试过其他几种方法,但也没有成功...我不确定为什么? - byrdr
2
如果所有提供的选项都无法正常工作,那么您肯定是在做其他错误的事情。 - dandavis
你能把searchData的内容也发布一下吗? - Mritunjay
要将深度嵌套的对象数组展平,您需要使用递归。请查看此文章获取解决方案。 - Talha Awan
显示剩余2条评论
14个回答

86

您可以像下面这样使用 Array.concat

var arr = [['object1', 'object2'],['object1'],['object1','object2','object3']];
var flattened = [].concat.apply([],arr);
flattened将是您期望的数组。ES 2020提供了flat,以及flatMap(如果您想要迭代),用于展平列表的嵌套列表:
[['object1'], ['object2']].flat() // ['object1', 'object2']

2
由于某些原因,它返回一个空数组。有任何想法为什么会发生这种情况? - byrdr
1
它适用于答案中提供的数组。但出于某种原因,我的数组返回 [ ]。 - byrdr
@byrdr,你能发一下你具体想要做什么吗? - Mritunjay
2
@Mritunjay,你能否给你的代码添加一些解释说明吗? - Nishanth Matha
对我来说,两种方法都不起作用。我使用 json_files.map((json_file: File) => { json_file.text().then(value => a_nested_array.push(JSON.parse(value))) }); 来创建数组,并希望执行 a_nested_array.flat() ... 但嵌套的数组没有被展平。 - c0mr4t
显示剩余2条评论

18

一种递归解决方法用于深度(嵌套)扁平化:

function flatten(a) {
  return Array.isArray(a) ? [].concat.apply([], a.map(flatten)) : a;
}

使用ES6更加简洁:

var flatten = a => Array.isArray(a) ? [].concat(...a.map(flatten)) : a;

为了好玩,使用名为 F 的生成器,名字为 "flatten",懒惰地生成平坦化的值:

function *F(a) {
  if (Array.isArray(a)) for (var e of a) yield *F(e); else yield a;
}

>> console.log(Array.from(F([1, [2], 3])));
<< [ 1, 2, 3 ]

对于不熟悉生成器的人来说,yield *语法从另一个生成器中产生值。Array.from接受一个迭代器(例如调用生成器函数后的结果)并将其转换为数组。


11

如果你只需要简单的扁平化,这可能会起作用:

var arr = [['object1', 'object2'],['object1'],['object1','object2','object3']];
var flatenned = arr.reduce(function(a,b){ return a.concat(b) }, []);

若需要更复杂的压平操作,Lodash 提供了 flatten 函数,也许是您所需:https://lodash.com/docs#flatten

//Syntax: _.flatten(array, [isDeep])

_.flatten([1, [2, 3, [4]]]);
// → [1, 2, 3, [4]];

// using `isDeep` to recursive flatten
_.flatten([1, [2, 3, [4]]], true);
// → [1, 2, 3, 4];

展示为什么更喜欢使用[].reduce而不是_.flatten的好例子! - dandavis
@dandavis 嗯,他只需要指定 _.flatten 的可选参数以获得深度行为,或者调用 _.flattenDeep - user663031

5

您可以使用 flat() 方法:

const data = [ [{id:1}, {id:2}], [{id:3}] ];
const result = data.flat();
console.log(result);

// you can specify the depth

const data2 = [ [ [ {id:1} ], {id:2}], [{id:3}] ];
const result2 = data2.flat(2);

console.log(result2);

在您的情况下:

const data = [[{"_id":"55064111d06b96d974937a6f","title":"Generic Title","shortname":"generic-title","contents":"<p>The Healing Center offers practical, social, and spiritual support to individuals and families. Services include, but are not limited to: food and clothing, job skills training and job search assistance, auto repair (Saturdays only), mentoring, financial counseling, tutoring, prayer, life skills training, and helpful information about local community services.</p><p>Stay in touch with us:</p>","__v":0},{"_id":"5508e1405c621d4aad2d2969","title":"test english","shortname":"test-page","contents":"<h2>English Test</h2>","__v":0}],[{"_id":"550b336f33a326aaee84f883","shortname":"ok-url","title":"now english","contents":"<p>okokko</p>","category":"Transportation","__v":0}]]

const result = data.flat();

console.log(result);


5

使用ES6扩展运算符

Array.prototype.concat(...searchData)

或者

[].concat(...searchData)


3
你可以使用这个自定义的递归方法来扁平化任何嵌套的数组。
const arr = [
  [1, 2],
  [3, 4, 5],
  [6, [7, 8], 9],
  [10, 11, 12]
]

const flatenedArray = arr => {
  let result = [];
  if(!arr.constructor === Array) return;
  arr.forEach(a => {
    if(a.constructor === Array) return result.push(...flatenedArray(a));
    result.push(a);
  });
  return result;
}


console.log(flatenedArray(arr)); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

2

递归地将数组扁平化:

function flatten(array) {
   return !Array.isArray(array) ? array : [].concat.apply([], array.map(flatten));
}
 
var yourFlattenedArray = flatten([[{"_id":"55064111d06b96d974937a6f","title":"Generic Title","shortname":"generic-title","contents":"<p>The Healing Center offers practical, social, and spiritual support to individuals and families. Services include, but are not limited to: food and clothing, job skills training and job search assistance, auto repair (Saturdays only), mentoring, financial counseling, tutoring, prayer, life skills training, and helpful information about local community services.</p><p>Stay in touch with us:</p>","__v":0},{"_id":"5508e1405c621d4aad2d2969","title":"test english","shortname":"test-page","contents":"<h2>English Test</h2>","__v":0}],[{"_id":"550b336f33a326aaee84f883","shortname":"ok-url","title":"now english","contents":"<p>okokko</p>","category":"Transportation","__v":0}]]
);

log(yourFlattenedArray);

function log(data) {
  document.write('<pre>' + JSON.stringify(data, null, 2) + '</pre><hr>');
}
* {font-size: 12px; }


1
那个可行!谢谢,我得分解这段代码。那为什么这一个运行了而其他的没有? - byrdr
1
在检查数组性质两次的地方有一些模糊的不符合DRY原则的东西。 - user663031
很奇怪,我错了。当我用包含数组的变量替换数组时,我再次返回了 [ ]。 - byrdr
1
@byrdr:你有几个已经验证过可以工作的解决方案,但是你报告了同样的问题。这应该告诉你问题出在其他地方。这些数据来自XHR请求吗?如果是,你是否在记录数据之前等待响应? - Lye Fish
1
@byrdr:猜测没有实际的代码和记录,这是不值得的。你可以直接提供正在运行的实际代码和记录。 - Lye Fish
显示剩余8条评论

2

我的解决方案是将一个对象数组展平并返回一个单一的数组。

flattenArrayOfObject = (arr) => {
  const flattened = {};

  arr.forEach((obj) => {
    Object.keys(obj).forEach((key) => {
      flattened[key] = obj[key];
    });
  });

  return flattened;
};

示例

const arr = [
  {
    verify: { '0': 'xyzNot verified', '1': 'xyzVerified' },
    role_id: { '1': 'xyzMember', '2': 'xyzAdmin' },
    two_factor_authentication: { '0': 'No', '1': 'Yes' }
  },
  { status: { '0': 'xyzInactive', '1': 'Active', '2': 'xyzSuspend' } }
]

flattenArrayOfObject(arr)

// {
//   verify: { '0': 'xyzNot verified', '1': 'xyzVerified' },
//   status: { '0': 'xyzInactive', '1': 'Active', '2': 'xyzSuspend' },
//   role_id: { '1': 'xyzMember', '2': 'xyzAdmin' },
//   two_factor_authentication: { '0': 'No', '1': 'Yes' }
// }

2
let functional = {
    flatten (array) {
        if (Array.isArray(array)) {
            return Array.prototype.concat(...array.map(this.flatten, this));
        }

        return array;
    }
};

functional.flatten([0, [1, 2], [[3, [4]]]]); // 0, 1, 2, 3, 4

1
这个答案是使用 ECMAScript 2015 编写的,不属于 [tag:javascript] 标签范畴。除非该问题的标签列表中已添加了适当的标签,否则应该提供传统的 JavaScript 答案。 - user4639281

2

我注意到有些人在使用递归,但这种方法不太经济,尤其是新的ES6标准已经为我们提供了扩展操作符。当你将项目推入主数组时,只需使用...,它会自动添加扁平化对象。像这样:

array.push(...subarray1)    // subarray1 = [object1, object2]
array.push(...subarray2)    // subarray2 = [object3]
array.push(...subarray3)    // subarray3 = [object4,object5, object6]
// output -> array = [object1, object2, object3, object4, object5, object6]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接