【问题标题】:A count of JSON rows that have Objects, excluding rows that are null具有对象的 JSON 行的计数,不包括为空的行
【发布时间】:2018-06-16 22:06:07
【问题描述】:

我正在使用 API 生成访问网页的平均时间,然后将所有返回值的总和除以 API 中设置的天数。

let avgtime = 0;

for (i in data) {
  if (data[i].avg_time_on_site) {
    avgtime += data[i].avg_time_on_site;
  }
}
$("#avgtime").html(avgtime / datePeriod);

datePeriod 是 API 返回的总天数。例如,如果 datePeriod 设置为 30,它将返回 avgtime 的最后 30 天。

avgtime += data[i].avg_time_on_site; 的 sn-p 从 JSON 中返回所有 avg_time_on_site 作为总和,然后除以 datePeriod 以获得设定天数 $("#avgtime").html(avgtime / datePeriod); 的平均值。

但是,我的问题是,这仅在网页每天都有返回值时才有效。如果网页在一天内没有被访问,如下面的示例 JSON 中所示,avgtime 将不正确,因为它将所有返回值的总和除以总天数,而不是包含行的总天数。

{
   "2017-12-30":[],
   "2017-12-31":{
      "nb_uniq_visitors":1,
      "nb_visits":1,
      "avg_time_on_site":41,
   },
   "2018-01-01":{
      "nb_uniq_visitors":1,
      "nb_visits":2,
      "avg_time_on_site":52,
   },
   "2018-01-02":[],
   "2018-01-03":{
      "nb_uniq_visitors":1,
      "nb_visits":3,
      "avg_time_on_site":83,
   },
   "2018-01-04":[]
}

我想将 $("#avgtime").html(avgtime / datePeriod); 中的函数 datePeriod 替换为另一个计算 JSON 中总行数的函数,不包括没有值的任何日期。

我曾尝试先研究解决方案,但不知所措。感谢您的帮助。

这是我的完整脚本

setTimeout(function() {
  $('#DateSelector').val('30').trigger("change")
}, 1000);

function datePeriod() {
  let datePeriod = $("#DateSelector").val();
  $("#DateShow").html(datePeriod);
  $.getJSON(`https://discovrbookings.innocraft.cloud/?module=API&method=API.get&format=json&idSite=2&period=day&date=last${datePeriod}&token_auth=68aa5bd12137f13255dcb98794b65dff`, (data) => {
    //console.log(data);
    let avgtime = 0;

    for (i in data) {
      if (data[i].avg_time_on_site) {
        avgtime += data[i].avg_time_on_site;
      }
    }
    $("#avgtime").html(avgtime / datePeriod);
  });
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select name="DateSelector" id="DateSelector" onchange="datePeriod();">
   <option value="7">Last 7 Days</option>
   <option value="14">Last 14 Days</option>
   <option value="30">Last 30 Days</option>
   <option value="90">Last 90 Days</option>
   <option value="365">Last 365 Days</option>
</select>

<h2 id="avgtime"></h2>

【问题讨论】:

  • 只要在if 块中保留自己的计数即可。在循环之前将第二个 var 初始化为 0,然后在添加到 avgtime 时加一。
  • @ChrisG。对不起,我不太明白。你是在暗示吗,我把data[i].avg_time_on_site除以avg_time_on_sitelength。所以只计算avg_time_on_site?我曾尝试在此处执行求和,但无法得到有效响应。
  • 下面的答案说明了我的意思。
  • 请注意,这是一个非常奇怪的平均值。这是该期间的平均平均现场停留时间。您不是更喜欢该期间的平均用户在网站上的时间还是平均在网站上的访问时间?后者可能看起来像(0 + (1 * 41) + (2 * 52) + 0 + (3 * 83) + 0) / (0 + 1 + 2 + 0 + 3 + 0) =&gt; 249 / 6 ~&gt; 185
  • 或者看起来你可以使用 API 中的sum_visit_length

标签: javascript jquery json


【解决方案1】:

我建议您只使用另一个变量来跟踪循环中的天数。这样你就可以独立于datePeriod

let avgtime = 0;
//another variable, because you can't use datePeriod
let dayCount = 0;

for (i in data) {
  if (data[i].avg_time_on_site) {
    avgtime += data[i].avg_time_on_site;
    dayCount++;
  }
}
$("#avgtime").html(avgtime / dayCount);

【讨论】:

  • 那是完美的。谢谢,一旦可以,我会标记为正确答案。
  • 添加hasOwnProperty 将进一步改进它。
  • 我同意,此外它还完全消除了对“datePeriod”变量的需要。
  • @AGoranov 在他的 getJSON-Request 中没有使用 datePeriod
  • @Christian 啊,谢谢指正。在计算平均值时最好不要依赖检查的值。这应该只在循环内部使用一个附加变量来完成。
【解决方案2】:

我会建议一种不同的方法。使用map 将数据标准化,然后将reduce 归一化为聚合对象,最后将总时间除以访问次数。

请参阅我关于正在使用的奇数平均值问题的注释。在这里,我提供了一个,它给出了在提供的日期内每次访问所花费的平均时间。

const avg = visits => (({cnt, time}) => time / cnt)(Object.values(visits).map(
  // Normalize to [{cnt: 0, avg: 0}, {cnt: 1, avg: 41}, ...]
  day => ({cnt: day.nb_visits || 0, avg: day.avg_time_on_site || 0})
).reduce(
  // combine to {count: 6, time: 394}
  (totals, day) => ({cnt: totals.cnt + day.cnt, time: totals.time + day.cnt * day.avg}), 
  {cnt: 0, time: 0}
))

avg(visits) //=> 65.666666666667

这可以通过使用sum_visit_date 而不是avg_time_on_site 来稍微简化:你可以跳过乘法。但这是一个很小的变化。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-31
    • 1970-01-01
    • 1970-01-01
    • 2020-08-27
    相关资源
    最近更新 更多