在给定维度上聚合数组数据

时间:2016-12-14 04:25:44

标签: javascript algorithm data-structures

原谅n00b-ish问题,但我是数据结构的新手。我最近被要求将一个给定的数组聚合在另一个数组上,并产生一个基于树的结果。

有人可以给我一些关于如何获得这个输出的指示吗?

INPUT

TOTAL 29900
  Female <Female Total>
    Single <Single Female Total>
      India <Single Female Total India>
      England <Single Female Total England>
    Married <Married Female Total>
      India <Married Female Total India>
      England <Married Female Total England>
  Male <Male Total>
    Single <Single Male Total>
      India <Single Male Total India>
      England <Single Male Total England>
    Married <Married Male Total>
      India <Married Male Total India>
      England <Married Male Total England>

输出:为每个叶节点使用2 *个空格。

{{1}}

3 个答案:

答案 0 :(得分:6)

结果可以用嵌套对象表示,每个内部对象都是一个子树,其总数为:

{
  total: 29900,
  Female: {
    total: 10300,
    Single: {
      total: 4000,
      India: {
        total: 2400
      },
      ...
    },
    ...
  },
  ...
}

只需遍历所有条目,然后将值添加到相应的子树节点。

对于输出,您可以使用JSON.stringify并从中删除不必要的文本。

警告:以下剧透

&#13;
&#13;
const T = [
  ['COUNTRY', 'GENDER', 'MARITAL STATUS', 'SALES'],
  ['India', 'Female', 'Single', 2400],
  ['India', 'Male', 'Single', 5200],
  ['India', 'Female', 'Married', 4300],
  ['India', 'Male', 'Single', 3200],
  ['England', 'Female', 'Single', 1600],
  ['England', 'Female', 'Married', 2000],
  ['England', 'Male', 'Single', 4800],
  ['England', 'Male', 'Married', 6400],
]
const A = ['GENDER', 'MARITAL STATUS', 'COUNTRY']

function aggregate(T, A) {
  const [fields, ...data] = T
  const columns = A.map(name => fields.findIndex(it => name === it))
  const count = fields.length - 1
  const result = { total: 0 }
  data.forEach(values => {
    result.total += values[count]
    //Go through the tree path, reduce is used here
    //to avoid creating extra tracking variable for current position
    columns.reduce((ref, index) => {
      const key = values[index]
      const next = ref[key] || (ref[key] = { total: 0 })
      next.total += values[count]
      return next
    }, result)
  })
  return result
}
function pack(data) {
  return Object.keys(data).reduce((result, key) => {
    if (key !== 'total') {
      const name = key + " " + data[key].total
      result[name] = pack(data[key])
    }
    return result
  }, {})
}
function format(result) {
  return JSON.stringify(pack(result), null, 2)
  .replace(/[^A-z0-9\n\s]/g, '')
  .replace(/\n?\s*\n/g, '\n')
}
function output(it) {
  const result = "TOTAL " + it.total + format(it)
  console.log(result)
}
output(aggregate(T, A))
&#13;
&#13;
&#13;

答案 1 :(得分:2)

使用树结构的常用方法是将它们表示为嵌套对象,如DarkKnight's answer所示,然后从此数据结构中创建字符串表示。

在OP提供的情况下,另一种方法是首先对数据进行排序,然后直接从排序数据创建树的字符串表示,而不需要任何嵌套对象的中间数据结构。

给定要聚合的列数组,

@Override
public int getCount() {
    return items.size();
}

我们可以按以下列对数据进行排序:

['GENDER', 'MARITAL STATUS', 'COUNTRY']

从最后一行向后循环,在聚合时,我们可以自下而上构建树的字符串表示形式。最后一行与之前的第3行(COUNTRY)不同,它提供以下输出:

GENDER   STATUS   COUNTRY   SALES
Female   Single   India     2400
Female   Single   England   1600
Female   Married  India     4300
Female   Married  England   2000
Male     Single   India     5200
Male     Single   England   4800
Male     Married  India     3200
Male     Married  England   6400

之前的行在3级(COUNTRY)和2级(MARITAL STATUS)上有所不同,前面是当前输出:

      England 6400

在此之前的行之后:

    Married 9600
      India 3200
      England 6400

然后,第5行与前3行不同:

      England 4800
    Married 9600
      India 3200
      England 6400

依此类推,直到代表整个树:

  Male 19600
    Single 10000
      India 5200
      England 4800
    Married 9600
      India 3200
      England 6400

以下是工作代码(符合ES3),演示了该方法。

Total 29900
  Female 10300
    Single 4000
      India 2400
      England 1600
    Married 6300
      India 4300
      England 2000
  Male 19600
    Single 10000
      India 5200
      England 4800
    Married 9600
      India 3200
      England 6400

答案 2 :(得分:2)

Tree是实现此问题的不错选择。您也可以在一次性通行证中进行聚合。基本理念是

  1. 按给定列对数据进行排序。

  2. 循环数组,检查给定列的值

    2.1如果列的值与上一行

    相同,则汇总组计数

    2.2输出组名称和计数,如果列的值与上一行不同

  3. 这是一个我引导CS学生完成作业的例子,与你的作业非常相似。

    Here处的sumaryStage3方法实现了步骤2的逻辑。

    请忽略代码风格和质量。这不是我的代码。