将求和列表分成满足条件的组的问题

时间:2020-08-10 03:01:56

标签: c# algorithm

我有一个交易记录列表,并带有相应的金额。

    public class Invoice
    {
        public Invoice(string TransactionReference, double Amount)
        {
            this.TransactionReference = TransactionReference;
            this.Amount = Amount;
        }
    
        public string TransactionReference { get; set; }
        public double Amount { get; set; }
    
    }

    List<Invoice> items = new List<Invoice>() {
        new Invoice("808861", -45.85),
        new Invoice("822634", -144.32),
        new Invoice("822635", -56.63),
        new Invoice("835308", 2970.55),
        new Invoice("835309", 869.36),
        new Invoice("835310", 3050.73),
        new Invoice("835311", 657.74),
        new Invoice("835312", 168.42),
        new Invoice("835348", 2922.69),
        new Invoice("835349", 324.5),
        new Invoice("835350", 906.3),
        new Invoice("835351", 420.21),
        new Invoice("835352", 851.7),
        new Invoice("838880", 158.43),
        new Invoice("838881", 2062.46),
        new Invoice("838882", 567.26),
        new Invoice("838883", 40.96),
        new Invoice("838884", 207.16),
        new Invoice("838889", 2726.13),
        new Invoice("838890", 29.25),
        new Invoice("838891", 1458.28),
        new Invoice("838892", 219.58),
        new Invoice("839930", 2791.99),
        new Invoice("839931", 455.47),
        new Invoice("839932", 514.94),
        new Invoice("839934", 666.78),
        new Invoice("840758", -341.34),
        new Invoice("855741", -113.55),
        new Invoice("855973", -85.46),
        new Invoice("866848", -39.53),
        new Invoice("877471", -58.17),
        new Invoice("877472", -58.17),
        new Invoice("878790", -459.53),
        new Invoice("892869", -6353.36)
};

我希望在满足以下条件的情况下将交易历史记录分为许多小组:

  1. 每组最多包含26个交易记录。
  2. 每组的总金额必须大于0。
  3. 最后一组包含历史记录,只要条件大于0。

下面我不加区别地写了计算交易的总试用额,但最终组仍小于0。

private static void ShowSumOf26Invoice( List<Invoice> list, int from, int to )
{
    if (list.Count > 26)
    {
        Console.WriteLine("Total amount from: " + from + " to " + to + " : " + items.GetRange(0,26).Sum(x => x.Amount));
        items.RemoveRange(from - 1, 26);
        from = from - 1 + 26;
        to = to + 26;
        ShowSumOf26Invoice(items, from, to);
    }
    else
    {
        Console.WriteLine("Total amount from: " + from + " to " + (to - 26 + items.Count) + " : " + items.Sum(x => x.Amount));
    }
}
    
static void Main(string[] args)
{
    Console.WriteLine( "Total amount: " + items.Sum( x => x.Amount ) );
    int from =  1;
    int to   = 26;
    ShowSumOf26Invoice( items, from, to );
    
    Console.WriteLine("Press any key to end the program!");
    Console.ReadKey();
}

这是发票的模型。

public class Invoice
{
    public Invoice(string TransactionReference, double Amount)
    {
        this.TransactionReference = TransactionReference;
        this.Amount = Amount;
    }

    public string TransactionReference { get; set; }
    public double Amount { get; set; }

}

您能给我一些解决这个问题的方法吗? 非常感谢!

1 个答案:

答案 0 :(得分:0)

您可以在单个Linq表达式中进行操作,如下所示:

List<String> messages = listOfInvoices
    .Select( ( inv, idx ) => ( inv, idx, batch: idx / 26 ) )
    .GroupBy( t => t.batch )
    .Select( grp => (
        batch: grp.Key,
        from : grp.First().inv.TransactionReference,
        to   : grp.Last() .inv.TransactionReference,
        count: grp.Count(),
        total: grp.Sum( t => t.inv.Amount )
    ))
//  .Where( batch => batch.total >= 0 )
    .Select( b => "Total for batch {0:N0} ({1:N0} invoices from {2} to {3}) is {4:C}".Fmt( b.batch + 1, b.count, b.from, b.to, b.total ) )
    .ToList();

为简洁起见,上面的Linq表达式使用此扩展方法:

static class StringExtensions
{
    public static String Fmt( this String format, params Object[] args )
    {
        return String.Format( CultureInfo.CurrentCulture, format, args );
    }
}

此外,对于Decimal,您应该使用Amount。不要使用doubleWhy not use Double or Float to represent currency?


这是您可以复制并粘贴到DotNetFiddle.net的整个程序,以查看其工作原理(选择“编译器:.NET Core 3.1”):

using System;
using System.Linq;
using System.Globalization;
using System.Collections.Generic;

public class Invoice
{
    public Invoice( String transactionReference, Decimal amount )
    {
        this.TransactionReference = transactionReference;
        this.Amount               = amount;
    }

    public String  TransactionReference { get; }
    public Decimal Amount               { get; }

}

static class StringExtensions
{
    public static String Fmt( this String format, params Object[] args )
    {
        return String.Format( CultureInfo.CurrentCulture, format, args );
    }
}
                    
public class Program
{
    public static void Main()
    {
        List<Invoice> listOfInvoices = new List<Invoice>() {
            new Invoice("808861",   -45.85M), //  0
            new Invoice("822634",  -144.32M), //  1
            new Invoice("822635",   -56.63M), //  2
            new Invoice("835308",  2970.55M), //  3
            new Invoice("835309",   869.36M), //  4
            new Invoice("835310",  3050.73M), //  5
            new Invoice("835311",   657.74M), //  6
            new Invoice("835312",   168.42M), //  7
            new Invoice("835348",  2922.69M), //  8
            new Invoice("835349",    324.5M), //  9
            new Invoice("835350",    906.3M), // 10
            new Invoice("835351",   420.21M), // 11
            new Invoice("835352",    851.7M), // 12
            new Invoice("838880",   158.43M), // 13
            new Invoice("838881",  2062.46M), // 14
            new Invoice("838882",   567.26M), // 15
            new Invoice("838883",    40.96M), // 16
            new Invoice("838884",   207.16M), // 17
            new Invoice("838889",  2726.13M), // 18
            new Invoice("838890",    29.25M), // 19
            new Invoice("838891",  1458.28M), // 20
            new Invoice("838892",   219.58M), // 21
            new Invoice("839930",  2791.99M), // 22
            new Invoice("839931",   455.47M), // 23
            new Invoice("839932",   514.94M), // 24
            new Invoice("839934",   666.78M), // 25
            new Invoice("840758",  -341.34M), // 26
            new Invoice("855741",  -113.55M), // 27
            new Invoice("855973",   -85.46M), // 28
            new Invoice("866848",   -39.53M), // 29
            new Invoice("877471",   -58.17M), // 30
            new Invoice("877472",   -58.17M), // 31
            new Invoice("878790",  -459.53M), // 32
            new Invoice("892869", -6353.36M)  // 33
        };
        
        List<String> messages = listOfInvoices
            .Select( ( inv, idx ) => ( inv, idx, batch: idx / 26 ) )
            .GroupBy( t => t.batch )
            .Select( grp => (
                batch: grp.Key,
                from : grp.First().inv.TransactionReference,
                to   : grp.Last() .inv.TransactionReference,
                count: grp.Count(),
                total: grp.Sum( t => t.inv.Amount )
            ))
//          .Where( batch => batch.total >= 0 )
            .Select( b => "Total for batch {0:N0} ({1:N0} invoices from {2} to {3}) is {4:C}".Fmt( b.batch + 1, b.count, b.from, b.to, b.total ) )
            .ToList();
        
        foreach( String message in messages )
        {
            Console.WriteLine( message );
        }
    }
}