【问题标题】:How to sum duplicates in an array如何对数组中的重复项求和
【发布时间】:2018-01-18 20:12:04
【问题描述】:

我正在创建一个chart,我已经成功完成了,但我有很多重复。

下面是一个示例我从中检索数据以显示在我的条形图上。

如何对从 检索到的重复值求和?

:

<counts>
    <serial>3123111</serial>
    <scans>3</scans>
    <prints>1</prints>
    <copies>0</copies>
</counts>
<counts>
    <serial>3123111</serial>
    <scans>0</scans>
    <prints>2</prints>
    <copies>0</copies>
</counts>
<counts>
    <serial>AHTSD111</serial>
    <scans>0</scans>
    <prints>1</prints>
    <copies>2</copies>
</counts>
<counts>
    <serial>AHTSD111</serial>
    <scans>0</scans>
    <prints>1</prints>
    <copies>2</copies>
</counts>

我用于条形图的预期结果如下:

<counts>
    <serial>3123111</serial>
    <scans>3</scans>
    <prints>3</prints>
    <copies>0</copies>
</counts>
<counts>
    <serial>AHTSD111</serial>
    <scans>0</scans>
    <prints>2</prints>
    <copies>4</copies>
</counts>

检索到的数据并推送到图表数据,我知道我必须执行一个循环来对每个序列号的扫描、打印、副本的值求和,但我仍然不断收到重复的值,我只是把代码遗漏了。

$.ajax({ 网址:“http://localhost5/api/”, 数据类型:'xml', 方法:“获取”, 成功:函数(数据){

                var parser = new DOMParser();
                var xmlDoc = parser.parseFromString(data, "text/html");
                data = xmlDoc.getElementsByTagName("JobCounts");

                var items = [];

                var serial, prints, copies, scans;

                function getAsText(parent, name) {
                    return parent.getElementsByTagName(name)[0].textContent
                }

                function getAsInt(parent, name) {
                    return parseInt(getAsText(parent, name));
                }

                for (i = 0; i < data.length; i++) {
                    items.push({
                        serial: getAsText(data[i], "serial"),
                        prints: getAsInt(data[i], "prints"),
                        copies: getAsInt(data[i], "copies"),
                        scans: getAsInt(data[i], "scans")
                    });


                }

                items = items.reduce((a, c) => {

                    var same = a.find(v => v.serial == c.serial);
                    console.log(same);
                    if (same) {
                        same.prints += c.prints;
                        same.copies += c.copies;
                        same.scans += c.scans;
                    } else {
                        a.push(c);
                    }
                    return a;
                }, []);

// "https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.4.0/Chart.min.js" // 我正在使用的 JS 图表库

                var chartdata = {
                    labels: serial,
                    title: "Date",

                    datasets: [
                        {
                            label: 'Copies',
                            backgroundColor: 'rgba(0,255,0,0.6)',
                            data: copies
                       }
                    ]

                };
                var ctx = $("#mycanvas");

                var options = {
                    responsive: true,
                    title: {
                        display: true,
                        position: "top",
                        text: "DashBoard",
                        fontSize: 12,
                        fontColor: "#111"
                    },
                    legend: {
                        display: true,
                        position: "bottom",
                        labels: {
                           fontSize: 9
                        }
                    },
                    scales: {
                        yAxes: [{
                                ticks: {
                                    beginAtZero: true

                            }
                        }]
                    }
                };
                var barGraph = new Chart(ctx, {
                    'type': 'bar',
                    data: chartdata,
                    options : options,
                    "categoryField": "date",
                    "categoryAxis": {
                       "autoGridCount": false,
                       "gridCount": chartdata.length,
                        "gridPosition": "start",
                        "labelRotation": 90,
                        "startOnAxis": false,
                        "title":"Date"
                    }


                });
            },

            error: function (data) {
                console.log(data);
            }
        });
    }

【问题讨论】:

  • 您可以将信息存储在单个对象数组中,而不是将信息存储在 3 个不同的数组中,这样可以更轻松地合并具有相同 serial 编号的对象。此外,示例 JSON DATA 看起来更像 XML
  • 它是 XML。我现在就试试
  • @trincot dataType: 您期望从服务器返回的数据类型。在这种情况下,应该是dataType: "xml"
  • @DannyFardyJhonstonBermúdez,确实正确!

标签: javascript xml xml xml javascript jquery json ajax


【解决方案1】:

您可以将信息存储在单个对象数组中,而不是将信息存储在 3 个不同的数组中,这样可以更轻松地合并具有相同 serial 编号的对象。

这就是我的意思:

var items = [];

function getAsText(parent, name){
    return parent.getElementsByTagName(name)[0].textContent
}

function getAsInt(parent, name){
    return parseInt(getAsText(parent, name));
}

for (i = 0; i < data.length; i++) {
   items.push({serial: getAsText(data[i], "serial"),
               prints: getAsInt(data[i], "prints"),
               copies: getAsInt(data[i], "copies"),
               scans: getAsInt(data[i], "scans")});
}


// Merge items with the same `serial` value;
items = items.reduce((a, c) => {
    var same = a.find(v => v.serial == c.serial);
    if(same){
       same.prints += c.prints;
       same.copies += c.copies;
       same.scans += c.scans;
    }else{
       a.push(c);
    }
    return a;
}, []);

【讨论】:

  • 这个pastebin.com/BGDM8r55 应该更快(我猜是O(n) 而不是O(N^2)?)免责声明 实际上并没有运行代码 - 但你应该明白
  • @giorgiga 最初的问题没有提到“更快”是一项要求
  • @guest271314 我的信息是对提图斯的建设性反馈,以便他/她可以改进他/她的答案,但这一定是在翻译中丢失了:-)
  • @giorgiga “改进他/她的回答”是什么意思?当前答案是否不符合 OP 中描述的要求?
  • @Titus // 我在 BarChart 中得到 [object object] 而不是实际值。当登录到控制台相同时,JSON Stringify 我得到了实际值,但不在条形图上。请问这是为什么? var chartdata = {标签:项目,标题:“仪表板”,数据集:[ {标签:'副本',背景颜色:'rgba(0,255,0,0.6)',数据:副本}]};
【解决方案2】:

您可以将每个counts 元素.children.map() 每个.tagName.textContent 迭代到一个对象、将对象推送到一个数组、迭代数组并递增每个SCANSPRINTS , 和 COPIES 属性,如果 SERIAL 匹配。

通过使用.forEach()Object.entries() 迭代结果数组,将JSON 转换为元素。

let data = `<counts>
<serial>3123111</serial>
<scans>3</scans>
<prints>1</prints>
<copies>0</copies>
</counts>

<counts>
<serial>3123111</serial>
<scans>0</scans>
<prints>2</prints>
<copies>0</copies>
</counts>

<counts>
<serial>AHTSD111</serial><scans>0</scans><prints>1</prints><copies>2</copies>
</counts>

<counts>
<serial>AHTSD111</serial><scans>0</scans><prints>1</prints><copies>2</copies>
</counts>`;

let parser = new DOMParser();
let xmlDoc = parser.parseFromString(data, "text/html");
let res = [];

for (let {counts:{SERIAL, SCANS, COPIES, PRINTS}} of 
    [...xmlDoc.querySelectorAll("counts")]
    .map(el =>
      ({counts:[...el.children]
               .reduce((o, {tagName, textContent}) =>
                 Object.assign(o, {[tagName]:textContent}), {})
       }))) {
  let curr = res.find(({counts:{SERIAL:s}}) => s === SERIAL); 
  if (!curr) {
    res.push({counts:{SERIAL, SCANS, COPIES, PRINTS}})
  } else {
    curr = curr.counts;
    curr.SCANS = +curr.SCANS + +SCANS;
    curr.PRINTS = +curr.PRINTS + +PRINTS;
    curr.COPIES = +curr.COPIES + +COPIES;
  }
}

res.forEach(o => {
  let key = Object.keys(o).pop();
  let parentNode = document.createElement(key);
  Object.entries(o[key])
  .forEach(([tagName, textContent]) => {
    let childNode = document.createElement(tagName)
    childNode.textContent = textContent;
    parentNode.appendChild(childNode);
    parentNode.appendChild(document.createElement("br"));
    document.body.appendChild(parentNode);
  })
  document.body.appendChild(document.createElement("br"));
})

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-22
    • 2016-11-12
    • 1970-01-01
    • 2019-08-20
    • 2021-05-12
    • 1970-01-01
    • 2019-10-25
    相关资源
    最近更新 更多