group_by哈希数组

时间:2018-02-02 05:30:30

标签: ruby hash

我有一个类似于此的Ruby哈希数组:

[
  {
    :account_id=>52,
    :amount_credit=>0.0,
    :amount_debit=>#<BigDecimal:7ff3f6f51c88,'0.1316837E7',9(18)>
  },
  {
    :account_id=>57,
    :amount_credit=>0.0,
    :amount_debit=>#<BigDecimal:7ff3f8157590,'0.0',9(18)>
  },
  ...
]

如果有多个条目具有相同的account_id,我会尝试按account_id对此进行分组。我会将它们分组并检查借方和贷方,如果借方高于贷方,然后借记 - 贷方,并将金额放入借方,反之亦然。

另一种情况

final_entries = []

entries = # the first entry that I put on the top

entries.group_by {|a| a[:account_id]}.each do |contents|
    if contents.length > 1

      get_id = []
      get_debit = []
      get_credit = []
      contents.each do |subject|
        get_id << subject.account_id
        get_debit << subject.amount_debit unless subject.amount_debit == 0
        get_credit << subject.amount_credit unless subject.amount_credit == 0
        if get_debit.sum > get_credit.sum
          total = get_debit.sum - get_credit.sum
          final_entries << { account_id: get_id[0], amount_credit: 0.0, amount_debit: total }
        else
          total = get_credit.sum - get_debit.sum
          final_entries << { account_id: get_id[0], amount_credit: total, amount_debit: 0.0 }
        end
      end
    else
      final_entries << contents
    end
  end
  

错误NoMethodError:未定义的方法`account_id&#39;为52:Fixnum

4 个答案:

答案 0 :(得分:1)

我使用了Uday使用的借记值,并提出了以下解决方案。

accounts = [{:account_id=>52, :amount_credit=>0.0, :amount_debit=>12.3434}, 
            {:account_id=>57, :amount_credit=>0.0, :amount_debit=>12.3434}, 
            {:account_id=>59, :amount_credit=>0.0, :amount_debit=>12.3434}, 
            {:account_id=>58, :amount_credit=>0.0, :amount_debit=>12.3434}, 
            {:account_id=>39, :amount_credit=>12.3434, :amount_debit=>0.0}, 
            {:account_id=>40, :amount_credit=>12.3434, :amount_debit=>0.0}, 
            {:account_id=>41, :amount_credit=>12.3434, :amount_debit=>0.0}, 
            {:account_id=>35, :amount_credit=>12.3434, :amount_debit=>0.0}, 
            {:account_id=>4, :amount_credit=>12.3434, :amount_debit=>0.0}, 
            {:account_id=>31, :amount_credit=>0.0, :amount_debit=>12.3434}, 
            {:account_id=>62, :amount_credit=>0.0, :amount_debit=>12.3434}, 
            {:account_id=>53, :amount_credit=>0.0, :amount_debit=>12.3434}, 
            {:account_id=>35, :amount_credit=>0.0, :amount_debit=>12.3434}, 
            {:account_id=>52, :amount_credit=>12.3434, :amount_debit=>0.0}, 
            {:account_id=>53, :amount_credit=>12.3434, :amount_debit=>0.0}, 
            {:account_id=>31, :amount_credit=>12.3434, :amount_debit=>0.0}, 
            {:account_id=>16, :amount_credit=>12.3434, :amount_debit=>0.0}]

accounts = accounts.group_by{|account| account[:account_id]}
                   .map {|id, records|
                      amount_credit = records.sum {|record| record[:amount_credit]}
                      amount_debit = records.sum {|record| record[:amount_debit]}
                      if amount_debit > amount_credit
                        {account_id: id,
                         amount_debit: amount_debit - amount_credit}
                      else
                        {account_id: id,
                         amount_credit: amount_credit - amount_debit}
                      end
                   }

p accounts

我在这里做的是我首先通过他们的account_id对帐户哈希进行分组,并在结果哈希上执行一个映射,以返回新数组的哈希值。

我相信这就是你在这里看到的。希望这会有所帮助。

我得到的结果是:

[{:account_id => 52,
  :amount_credit => 0.0
}, {:account_id => 57,
  :amount_debit => 12.3434
}, {:account_id => 59,
  :amount_debit => 12.3434
}, {:account_id => 58,
  :amount_debit => 12.3434
}, {:account_id => 39,
  :amount_credit => 12.3434
}, {:account_id => 40,
  :amount_credit => 12.3434
}, {:account_id => 41,
  :amount_credit => 12.3434
}, {:account_id => 35,
  :amount_credit => 0.0
}, {:account_id => 4,
  :amount_credit => 12.3434
}, {:account_id => 31,
  :amount_credit => 0.0
}, {:account_id => 62,
  :amount_debit => 12.3434
}, {:account_id => 53,
  : amount_credit => 0.0
}, {:account_id => 16,
  :amount_credit => 12.3434
}]

答案 1 :(得分:1)

让我来看看你现有的代码:

entries.group_by {|a| a[:account_id]}.each do |contents|
  if contents.length > 1 # This will always be true, since contents is an Array of [account_id, [entries]]
    get_id = []
    get_debit = []
    get_credit = []
    contents.each do |subject| # Again, contents is a Hash of account_id => [entries]; should be |id, entries|
      get_id << subject.account_id  # Even if this was a single entry, this wouldn't work since it's a Hash; should be subject[:account_id]
      get_debit << subject.amount_debit unless subject.amount_debit == 0  # Fails for the same reason
      get_credit << subject.amount_credit unless subject.amount_credit == 0  # Fails for the same reason
      if get_debit.sum > get_credit.sum  # We're summing what we saved, but excluded 0 values even though they don't change the sum?
        total = get_debit.sum - get_credit.sum  # Avoid summing again
        final_entries << { account_id: get_id[0], amount_credit: 0.0, amount_debit: total }
      else
        total = get_credit.sum - get_debit.sum
        final_entries << { account_id: get_id[0], amount_credit: total, amount_debit: 0.0 }
      end
    end
  else
    final_entries << contents
  end
end

现在我会做什么:

final_entries = entries
  .group_by { |entry| entry[:account_id] }
  .map do |id, acct_entries|
    return acct_entries.first if acct_entries.size == 1

    credit = acct_entries.map { |entry| entry[:amount_credit] }.sum
    debit = acct_entries.map { |entry| entry[:amount_debit] }.sum

    if credit > debit
      credit -= debit
      debit = 0.0
    else
      debit -= credit
      credit = 0.0
    end
    { account_id: id, amount_credit: credit, amount_debit: debit }
  end

答案 2 :(得分:0)

我的两分钱:

grep

值得一提的是Enumerable#sum仅适用于Ruby 2.4.0及更高版本。

答案 3 :(得分:0)

final_entries = []
entries.group_by {|a| a[:account_id]}.each do |key, value|
    if value.length > 1
      get_debit = []
      get_credit = []
      value.each do |subject|
        get_debit << subject[:amount_debit] if subject[:amount_debit] > 0
        get_credit << subject[:amount_credit] if subject[:amount_credit] > 0
      end
      if get_debit.sum > get_credit.sum
        total = get_debit.sum - get_credit.sum
        final_entries << { account_id: key, amount_credit: 0.0, amount_debit: total }
      else
        total = get_credit.sum - get_debit.sum
        final_entries << { account_id: key, amount_credit: total, amount_debit: 0.0 }
      end
    else
      final_entries << value[0]
    end
  end