如何使用正则表达式对数组中的 Javascript 对象进行排序

Posted

技术标签:

【中文标题】如何使用正则表达式对数组中的 Javascript 对象进行排序【英文标题】:How to sort Javascript objects in an array using regex 【发布时间】:2020-02-03 20:00:12 【问题描述】:

我正在调用 API 并获取包含大量对象的数组。数组中有数百个对象,其中一个简短的 sn-p 看起来像这样:

[
    
      "name": "total_kills_glock",
      "value": 70
    ,
    
      "name": "total_kills_mac10",
      "value": 39
    ,
    
      "name": "total_kills_ump45",
      "value": 136
    ,
    
      "name": "total_shots_glock",
      "value": 1262
    ,
    
      "name": "total_hits_glock",
      "value": 361
    
    
      "name": "total_shots_mac10",
      "value": 862
    ,
    
      "name": "total_hits_mac10",
      "value": 261
    ,
    
      "name": "total_shots_ump45",
      "value": 1610
    ,
    
      "name": "total_hits_ump45",
      "value": 598
    
]

有没有办法使用正则表达式对数组进行排序,看起来像这样:

[
  
    "name": "glock",
    "kills": 70,
    "shots": 1262,
    "hits": 361
  ,
  
    "name": "mac10",
    "kills": 39,
    "shots": 862,
    "hits": 261
  ,
  
    "name": "ump45",
    "kills": 136,
    "shots": 1610,
    "hits": 598
  
]

【问题讨论】:

您应该先尝试并分享您的代码,而不是直接说明需求。我没有看到有人试图解决这个问题。 啊,那是我的错,我没有放到目前为止我创建的代码。我只会在我知道我尝试了几个小时的解决方案但仍然无法找到答案时发布。 @Leon 请检查我的答案***.com/a/58254128/12167785 【参考方案1】:

也许循环比使用正则表达式创建一个新对象更有帮助,我不确定我以前是否见过。

var rawData = [  "name": "total_kills_glock", "value": 70 ,  "name": "total_kills_mac10", "value": 39 ,  "name": "total_kills_ump45", "value": 136 ,  "name": "total_shots_glock", "value": 1262 ,  "name": "total_hits_glock", "value": 361 ,  "name": "total_shots_mac10", "value": 862 ,  "name": "total_hits_mac10", "value": 261 ,  "name": "total_shots_ump45", "value": 1610 ,  "name": "total_hits_ump45", "value": 598  ];

var gunStats = [
    "name": "glock",
    "kills": 0,
    "shots": 0,
    "hits": 0
,

    "name": "mac10",
    "kills": 0,
    "shots": 0,
    "hits": 0
  ,
  
    "name": "ump45",
    "kills": 0,
    "shots": 0,
    "hits": 0
  
];

rawData.forEach((item)  =>  
    if (item.name.includes("glock")) 
        applyStatsToGun(item, "glock");
    

    if (item.name.includes("mac10")) 
        applyStatsToGun(item, "mac10");
    

    if (item.name.includes("ump45")) 
        applyStatsToGun(item, "ump45");
    

);


function applyStatsToGun(item, gunName) 
    if (item.name.includes(gunName)) 

        if (item.name.includes("kills")) 
            var gun = gunStats.find((gun) => gun.name == gunName);
            gun.kills += item.value;
        

        if (item.name.includes("shots")) 
            var gun = gunStats.find((gun) => gun.name == gunName);
            gun.shots += item.value;
        

        if (item.name.includes("hits")) 
            var gun = gunStats.find((gun) => gun.name == gunName);
            gun.hits += item.value;
        
    



console.log(gunStats);

如果您不知道要对枪名字符串进行硬编码,假设首先有数百个您想要获取所有唯一名称的列表,然后遍历列表并解析 name.split("_")[3] 中的第三个元素遍历该列表并应用该值,而不是对这些值进行硬编码

【讨论】:

谢谢,这也很好用!这与我编写的初始代码相似,但无法弄清楚为什么它不起作用。我从你写的这个代码示例中学到了很多东西!【参考方案2】:

您可以拆分字符串并解构项目并将对象作为同一组的哈希表。最后从哈希表中取值。

var data = [ name: "total_kills_glock", value: 70 ,  name: "total_kills_mac10", value: 39 ,  name: "total_kills_ump45", value: 136 ,  name: "total_shots_glock", value: 1262 ,  name: "total_hits_glock", value: 361 ,  name: "total_shots_mac10", value: 862 ,  name: "total_hits_mac10", value: 261 ,  name: "total_shots_ump45", value: 1610 ,  name: "total_hits_ump45", value: 598 ],
    result = Object.values(data.reduce((r,  name, value ) => 
        var [, type, name] = name.split('_');
        r[name] = r[name] ||  name ;
        r[name][type] = value;
        return r;
    , ));

console.log(result);
.as-console-wrapper  max-height: 100% !important; top: 0; 

【讨论】:

【参考方案3】:

下面是一个纯函数式解决方案,它结合了一些有用的技术。请注意,您可以在代码的其他地方重用部分函数。此外,通过这种方式,计算可以并行化和分布式(尽管 javascript 尚不存在)。

 let raw = [
    "name": "total_kills_glock", "value": 70,
    "name": "total_kills_mac10", "value": 39,
    "name": "total_kills_ump45", "value": 136,
    "name": "total_shots_glock", "value": 1262,
    "name": "total_hits_glock", "value": 361,
    "name": "total_shots_mac10", "value": 862,
    "name": "total_hits_mac10", "value": 261,
    "name": "total_shots_ump45", "value": 1610,
    "name": "total_hits_ump45", "value": 598
];

//you can use any parsing technique here, including regexp
const parse = name =>  
    const a = name.split("_"); 
    return  key: a[2], metric: a[1] 
;

const groupBy = getKey => (rv, x) => 
    (rv[getKey(x)] = rv[getKey(x)] || []).push(x);
    return rv;
;

//converts [key,metric,value,...] to name:key, m1:v1, m2:v2,... 
const recombine = arr => Object.assign(name: arr[0].key,
    ...Array.from(arr, (key, metric, value) => ([metric]: value) ));

const groupedByKey = raw
            .map( (name, ...attrs) => (...parse(name), ...attrs))
            .reduce(groupBy(x => x.key),);

const result = Object.values(groupedByKey).map(recombine);
console.log(result);

我没有对它进行基准测试,但如果它在某些数据集上的表现优于 Nick 的解决方案,我不会感到惊讶。也就是说,维护起来可能并不容易,具体取决于团队和技能。

【讨论】:

【参考方案4】:

请检查一下。

let arr=[] //your array
let map=new Map();
arr.forEach((obj)=>
let x=obj.name.split('_');
map.set(x[2],"name":x[2],...map.get(x[2]),[x[1]]:obj.value)

);
console.log([...map.values()]);

如果您需要,请随时使用我的回复https://repl.it/repls/PoisedEasyZettabyte。

【讨论】:

【参考方案5】:

您可以使用reduce() 方法对数组项进行分组,split() 方法从name 字符串中提取名称和操作。

var data = [ "name": "total_kills_glock", "value": 70 ,  "name": "total_kills_mac10", "value": 39 ,  "name": "total_kills_ump45", "value": 136 ,  "name": "total_shots_glock", "value": 1262 ,  "name": "total_hits_glock", "value": 361 ,  "name": "total_shots_mac10", "value": 862 ,  "name": "total_hits_mac10", "value": 261 ,  "name": "total_shots_ump45", "value": 1610 ,  "name": "total_hits_ump45", "value": 598  ];

var result = data.reduce((acc, curr) => 
  let words = curr.name.split('_');
  let name = words[2];
  let action = words[1];

  let item = acc.find(item => item.name === name);

  if (item) 
    item[action] = curr.value;
   else 
    acc.push(
      "name": name,
      [action]: curr.value
    );
  

  return acc;
, []);

console.log(result);

【讨论】:

这真的很好用!我认为唯一的解决方案是使用正则表达式,但我错了。我将把它应用到我的应用程序的其他部分。 很高兴听到@Leon。正则表达式当然有效,但 split() 就足够了,非常适合这个简单的问题。【参考方案6】:

这是一种方法,使用正则表达式从原始名称中提取名称和数据类型,然后基于此构建一个对象:

const raw = [
    "name": "total_kills_glock",
    "value": 70
  ,
  
    "name": "total_kills_mac10",
    "value": 39
  ,
  
    "name": "total_kills_ump45",
    "value": 136
  ,
  
    "name": "total_shots_glock",
    "value": 1262
  ,
  
    "name": "total_hits_glock",
    "value": 361
  ,
  
    "name": "total_shots_mac10",
    "value": 862
  ,
  
    "name": "total_hits_mac10",
    "value": 261
  ,
  
    "name": "total_shots_ump45",
    "value": 1610
  ,
  
    "name": "total_hits_ump45",
    "value": 598
  
];

var final = [];
var keys = [];
raw.forEach(v => 
  const m = v.name.match(/^total_([^_]+)_(.+)$/);
  const k = keys.indexOf(m[2]);
  if (k == -1) 
    var o =  name: m[2] ;
    o[m[1]] = v.value;
    final.push(o);
    keys.push(m[2]);
   else 
    final[k][m[1]] = v.value;
  
);
console.log(final);

【讨论】:

以上是关于如何使用正则表达式对数组中的 Javascript 对象进行排序的主要内容,如果未能解决你的问题,请参考以下文章

融职教育Web前端学习 第3章 JavaScript基础教程10 正则表达式

JavaScript中的正则表达式

javascript数组indexOf中使用的正则表达式

JavaScript中的正则表达式(终结篇)

javascript中字幕的正则表达式中的可变行数

javascript-如何在 json 字符串上使用正则表达式来搜索 JQuery 中的数据表列?