Javascript 使用ES6 reduce或map计算数组嵌套对象中的总和和百分比

Javascript 使用ES6 reduce或map计算数组嵌套对象中的总和和百分比,javascript,ecmascript-6,reduce,Javascript,Ecmascript 6,Reduce,如果标题不是特别清楚,请道歉。我在下面做了一个简短的可复制的例子,说明我正在尝试做的事情: var arrayOfPeopleStats = [ person1 = { this: { makes: 10, attempts: 15, pct: .666667 }, that: { makes: 12, attempts: 16, pct: .75 }, thos: { value: 10, rank: 24 }, them: { value: 15, ra

如果标题不是特别清楚,请道歉。我在下面做了一个简短的可复制的例子,说明我正在尝试做的事情:

var arrayOfPeopleStats = [
  person1 = { 
    this: { makes: 10, attempts: 15, pct: .666667 },
    that: { makes: 12, attempts: 16, pct: .75 },
    thos: { value: 10, rank: 24 },
    them: { value: 15, rank: 11 }
  },
  person2 = { 
    this: { makes: 5, attempts: 15, pct: .333333 },
    that: { makes: 10, attempts: 12, pct: .83333 },
    thos: { value: 4, rank: 40 },
    them: { value: 3, rank: 32 }
  },
  person3 = { 
    this: { makes: 14, attempts: 14, pct: 1 },
    that: { makes: 7, attempts: 8, pct: .875 },
    thos: { value: 12, rank: 12 },
    them: { value: 13, rank: 10 }
  }
]


var desiredOutput = [
  allPeople: {
    this: { makes: 29, attempts: 44, pct: .65909 },
    that: { makes: 29, attempts: 36, pct: .80555 },
    thos: { value: 26, rank: doesnt matter },
    them: { value: 31, rank: doesnt matter }
  }
]
arrayOfPeopleStats
是一个包含person对象的数组。每个person对象都有一对统计信息(本例中为this、that、this),每个统计信息都是一个对象,具有三个属性:make、attempts、steals或value、rank

我想对每个人在stat对象上的make、尝试和值进行求和,并为求和的数据计算新的
pct

我将很快发布我使用ES6 reduce所做的尝试,尽管我不确定这是解决这个问题的最佳方法。非常感谢您在这方面的任何帮助

arrayOfPeopleStats.reduce((a, v) => {
  a.allPeople.this = {
    makes: a.allPeople.this.makes + v.this,
    attempts: a.allPeople.this.attempts + v.this.attempts,
  };
  a.allPeople.that = {
    makes: a.allPeople.that.makes + v.that.makes,
    attempts: a.allPeople.that.attempts + v.that.attempts,
  };
  a.allPeople.thos = {
    value: a.allPeople.thos.value + v.thos.value,
  };
  a.allPeople.them = {
    value: a.allPeople.them.value + v.them.value,
  };
  a.allPeople.this.pct = a.allPeople.this.makes / a.allPeople.this.attempts
  a.allPeople.that.pct = a.allPeople.that.makes / a.allPeople.that.attempts
  return a;
}, {allPeople: {
    this: { makes: 0, attempts: 0, pct: 0 },
    that: { makes: 0, attempts: 0, pct: 0 },
    thos: { value: 0, rank: 0 },
    them: { value: 0, rank: 0 }
  }
}});

我忽略了排名,正如你所说的,这无关紧要,上面的解决方案总是0。我还选择了不将结果对象包装在数组中,正如您在所需结果中所做的那样。有关此API的解释,请参阅。

它将帮助您开始从类型的角度考虑数据

Person
是一个具有四个属性的对象

  • this
    是一个
    Stat
    对象(我们将很快定义)
  • 那是另一个
    Stat
    对象
  • thos
    这是一个
    Rank
    对象(我们也将定义它)
  • 它们
    是另一个
    等级
    对象
  • 为了继续,我们将
    Stat
    指定为具有三个属性的对象

  • 生成
    哪个是数字
  • 尝试
    哪个是另一个数字
  • pct
    哪个是另一个数字
  • 最后,
    Rank
    是一个具有两个属性的对象

  • 哪个是数字
  • rank
    哪个是另一个数字
  • 我们现在可以将
    arrayOfPeopleStats
    视为一个项目数组,其中每个项目都是Person类型的。为了组合相似的类型,我们定义了一种方法来
    创建我们类型的值,以及一种方法来
    concat
    (添加)它们

    我将首先定义较小的类型,
    Stat
    -

    const Stat =
      { create: (makes, attempts) =>
          ({ makes, attempts, pct: makes / attempts })
    
      , concat: (s1, s2) =>
          Stat .create
            ( s1.makes + s2.makes
            , s1.attempts + s2.attempts
            )
      }
    
    等级
    类型类似。您说过,
    rank
    的组合值是多少“无关紧要”,但这表明您必须做出选择。您可以选择一个或另一个,将两个值相加,或完全使用其他选项。在这个实现中,我们选择最高的
    rank
    值-

    const Rank =
      { create: (value, rank) =>
          ({ value, rank })
    
      , concat: (r1, r2) =>
          Rank .create
            ( r1.value + r2.value
            , Math .max (r1.rank, r2.rank)
            ) 
      }
    
    最后,我们实现了
    Person
    。我将
    this
    that
    thos
    this
    重命名为
    a
    b
    c
    d
    ,因为
    this
    是JavaScript中的一个特殊变量,我认为它使示例更容易理解;无论如何,你问题中的数据看起来都是假的。这里需要注意的是,
    Person.concat
    函数依赖于
    Stat.concat
    Rank.concat
    ,将每种类型的组合逻辑很好地分开-

    const Person =
      { create: (a, b, c, d) =>
          ({ a, b, c, d })
    
      , concat: (p1, p2) =>
          Person .create
            ( Stat .concat (p1.a, p2.a)
            , Stat .concat (p1.b, p2.b)
            , Rank .concat (p1.c, p2.c)
            , Rank .concat (p1.d, p2.d)
            )
      }
    
    现在,要组合数组中的所有
    person
    项,只需使用
    person.concat
    操作进行缩减即可-

    arrayOfPeopleStat .reduce (Person.concat)
    
    // { a: { makes: 29, attempts: 44, pct: 0.6590909090909091 }
    // , b: { makes: 29, attempts: 36, pct: 0.8055555555555556 }
    // , c: { value: 26, rank: 40 }
    // , d: { value: 31, rank: 32 }
    // }
    
    请注意,当您已经很好地定义了数据构造函数时,使用
    {…}
    手工写出数据既麻烦又容易出错。而是使用您类型的
    create
    功能-

    var arrayOfPeopleStat =
      [ Person .create
          ( Stat .create (10, 15)
          , Stat .create (12, 16)
          , Rank .create (10, 24)
          , Rank .create (15, 11)
          )
      , Person .create
          ( Stat .create (5, 15)
          , Stat .create (10, 12)
          , Rank .create (4, 40)
          , Rank .create (3, 32)
          )
      , Person .create
          ( Stat .create (14, 14)
          , Stat .create (7, 8)
          , Rank .create (12, 12)
          , Rank .create (13, 10)
          )
      ]
    
    与使用
    {…}
    手工写出数据相比,使用
    create
    函数的另一个优点是构造函数可以为您提供帮助。注意如何为
    Stat
    自动计算
    pct
    。这可以防止有人编写无效的统计数据,如
    pct
    属性不等于
    makes/attempts
    {makes:1,attempts:2,pct:3}
    。如果此数据的接收者未进行检查,我们无法确保
    pct
    属性的完整性。另一方面,使用我们的构造函数,
    Stat.create
    只接受
    makes
    尝试
    ,并自动计算
    pct
    字段,确保正确的
    pct

    构造函数还可以防止有人创建会导致错误的stat,例如
    stat.create(10,0)
    ,它将尝试为
    pct
    属性计算
    10/0
    (除以零错误)-

    const Stat =
      { create: (makes = 0, attempts = 0) =>
          attempts === 0
            ? { makes, attempts, pct: 0 }                // instead of throwing error
            : { makes, attempts, pct: makes / attempts } // safe to divide
    
      , concat: ...
      }
    
    最终这些选择取决于你。在这种情况下,另一个程序员可能会赞成错误。比如-

    Stat .create (10, 0)
    // Error: invalid Stat. makes (10) cannot be greater than attempts (0). attempts cannot be zero.
    
    当然,
    reduce
    的结果是相同的-

    arrayOfPeopleStat .reduce (Person.concat)
    
    // { a: { makes: 29, attempts: 44, pct: 0.6590909090909091 }
    // , b: { makes: 29, attempts: 36, pct: 0.8055555555555556 }
    // , c: { value: 26, rank: 40 }
    // , d: { value: 31, rank: 32 }
    // }
    
    展开下面的代码段,在您自己的浏览器中验证结果-

    const Stat=
    {创建:(创建、尝试)=>
    ({makes,attempts,pct:makes/attempts})
    ,concat:(s1,s2)=>
    统计,创建
    (s1.makes+s2.makes)
    ,s1.尝试次数+s2.尝试次数
    )
    }
    常数秩=
    {创建:(值、等级)=>
    ({值,秩})
    ,concat:(r1,r2)=>
    排名。创建
    (r1.value+r2.value)
    ,Math.max(r1.rank,r2.rank)
    ) 
    }
    警察=
    {创建:(a、b、c、d)=>
    ({a,b,c,d})
    ,concat:(p1,p2)=>
    人。创造
    (统计浓度(p1.a、p2.a)
    ,统计浓度(p1.b,p2.b)
    ,秩.concat(p1.c,p2.c)
    ,职级:concat(p1.d,p2.d)
    )
    }
    var数据=
    [个人,创建
    (统计创建(10,15)
    ,Stat.create(12,16)
    ,排名。创建(10,24)
    ,排名。创建(15,11)
    )
    ,Person.create
    (统计创建(5,15)
    ,Stat.create(10,12)
    ,排名。创建(4,40)
    ,排名。创建(3,32)
    )
    ,Person.create
    (统计创建(14,14)
    ,统计创建(7,8)
    ,排名。创建(12,12)
    ,排名。创建(13,10)
    )
    ]
    console.log(data.reduce(Person.concat)