如何将来自其他两个列表C#的元素按升序存储在列表中?

时间:2018-11-13 22:40:50

标签: c#

我遇到的问题是按升序显示列表中的项目。我了解造成此问题的问题,即我将帐户添加到列表中,然后将帐户添加到列表中,但是我不确定我可以通过其他方式执行此操作。结果应该是以创建帐户的顺序显示帐户,这取决于用户。因此,如您从下图所看到的,它首先存储并显示所有创建的支票帐户,然后是不正确的储蓄帐户。它应按创建顺序显示。从下面的图像中可以看到,这些项目已损坏。它应该先显示储蓄帐户1,然后显示支票帐户2,依此类推。

This is how the items are being displayed

这是将项目添加到此列表并造成问题的代码

List<Account> accounts = new List<Account>();

accounts.AddRange(caccounts);
accounts.AddRange(saccounts);

foreach (Account account in accounts)
{
    List<Transaction> transactions = account.closeMonth();

    allTransactions.AddRange(transactions);
}

此代码显示了我要添加帐户和帐户的列表

List<SavingsAccount> saccounts = new List<SavingsAccount>();
List<CheckingAccount> caccounts = new List<CheckingAccount>();
List<Transaction> allTransactions = new List<Transaction>();

这是我在支票类和储蓄类中具有的代码,这些代码将覆盖抽象帐户类中的关闭月份

public override List<Transaction> closeMonth()
{
    var transactions = new List<Transaction>();

    var endString = new Transaction();

    string reportString = ("Checking account: " + AccountID.ToString() + 
        " has a balance of $" + endingBalance.ToString());

    endString.EndOfMonth = reportString;
    transactions.Add(endString);

    return transactions;
}

这是AccountID的属性,我在支票和储蓄类中拥有此属性

class SavingsAccount : Account
{
    public override int AccountID { get; set; }
}

最初创建帐户时,这是分配AccountID的代码

if (checkingRadioButton1.Checked == true)
{
    _nextIndex++;
    transactionLabel5.Text = "Checking Account: #" + _nextIndex + 
        " created with a starting balance of $" + balance;
    accountTextBox1.Text = "" + _nextIndex;
    caccounts.Add(new CheckingAccount(balance)
    {
        AccountID = _nextIndex,
        Student = isStudent
    });
}
else if (savingsRadioButton2.Checked == true)
{
    _nextIndex++;
    transactionLabel5.Text = "Savings Account: #" + _nextIndex + 
        "   created with a starting balance of $" + balance;
    accountTextBox1.Text = "" + _nextIndex;
    saccounts.Add(new SavingsAccount(balance)
    {
        AccountID = _nextIndex,
        Senior = isSenior
    });
}

3 个答案:

答案 0 :(得分:2)

您可以在集合上使用OrderBy

var orderedTransactions = allTransactions.OrderBy(x=>x.AccountId).ToList();

当然,您需要具有该CreateDate或想要在对象中排序的任何属性。

答案 1 :(得分:1)

而不是使用此代码将帐户合并到一个列表中

 List<Account> accounts = new List<Account>();

        accounts.AddRange(caccounts);
        accounts.AddRange(saccounts);

        foreach (Account account in accounts)
        {
            List<Transaction> transactions = account.closeMonth();

            allTransactions.AddRange(transactions);
        }

您可以使用此代码

List<Account> accounts = new List<Account>();
            int saccountsAdded = 0;
            int caccountsAdded = 0;
            for (int i = 0; i < saccounts.Count + caccounts.Count; i++)
            {
                if(saccountsAdded == saccounts.Count)
                {
                    accounts[i] = caccounts[caccountsAdded++];
                    continue;
                }
                if (caccountsAdded == caccounts.Count)
                {
                    accounts[i] = saccounts[saccountsAdded++];
                    continue;
                }
                if (saccounts[saccountsAdded].AccountID > caccounts[caccountsAdded].AccountID)
                {
                    accounts[i] = caccounts[caccountsAdded ++];

                }
                else
                {
                    accounts[i] = saccounts[saccountsAdded ++];

                }
            }

在我的情况下,您是在对帐户进行合并时对其进行排序,然后将对您的帐户列表进行排序。 您也可以使用NoSaidTheCompiler的解决方案,唯一的区别是我同时对列表进行排序和填充,他首先填充列表,然后在填充列表之后进行排序

答案 2 :(得分:1)

简短的答案是,您可以使用Transactions扩展方法AccountID通过System.LinqOrderBy进行排序(连同对.SelectMany的方法调用将每个帐户的交易清单放平),然后再输出它们:

List<Transaction> transactions = accounts
    .OrderBy(a => a.AccountID)
    .SelectMany(a => a.closeMonth())
    .ToList();

其他想法

在回答您的问题时,我无法弄清楚为什么Account是抽象的,或者为什么CheckingAccountSavingsAccount会有一个单独的类,因为我不能看到两者之间的差异,并且在两个不同的类中使用完全相同的代码来覆盖所有这些抽象属性和方法,感觉太多余了。

考虑到这一点,我感到不得不分享一些想法,这些想法可能适用于您的特定情况,也可能不适用于您的特定情况。请注意,我以前从未编写过银行应用程序,因此可能有很多我没想到的事情-只是想分享一下,以防万一。

帐户

对我来说,帐户就是帐户。可能存在与一种或另一种类型关联的不同规则,但是可以由创建帐户的Bank定义这些规则,并且该类可以具有根据特定银行的政策设置的List<Rule> AccountRules (例如,支票帐户可能有最低余额,但储蓄帐户没有最低余额,或者它们的利率时间表不同,或者其他什么,但我认为这没有什么本质上的区别)。

但是,最后,帐户是十进制金额的存储库,可以通过WithdrawlDeposit(或Interest累积)进行更改。

交易

此外,closeMonth()方法对我来说真的很奇怪。它返回一个包含单个项目的List<Transaction>。相反,我认为Account应该有一个List<Transaction>,它是通过每个公共方法填充的,甚至可以平衡查询。然后可以查询此列表以获取特定时间范围内的活动,例如一个月或一年(通过过滤Transaction.Timestamp属性)。或者可以查询它以获取不同类型的事务(通过过滤Transaction.TransactionType属性)。

为了简化向列表中添加新事务的过程,我添加了一个private AddTransaction方法,该方法接受一个Transaction.Type和一个事务描述。然后,它创建Transaction并将其添加到列表中。还要注意,Transaction类会自动将当前的DateTime添加为Timestamp,因此无需在客户端担心这一点。

代码

为了防止在不同线程中同时调用DepositWithdrawl的竞争情况,我在访问lock()的任何代码周围添加了Balance块。 / p>

我还为ToString类的Transaction方法添加了覆盖,以便更轻松地输出每笔交易的详细信息。

另一个有趣的项目是,您可以使用decimal格式字符串将C设置为货币格式(即,如果您有decimal balance = 5M;,则可以执行balance.ToString("C")或{ {1}},字符串结果在美国为"{balance:C}",在英国为"$5.00"

所以这些类可能看起来类似于以下内容:

"£5.00"

因此,这就是一个示例,该示例以您在上面的表格中显示的相同顺序填充一个帐户列表,并举例说明了如何输出由该帐户ID排序的帐户的所有交易:

public class Transaction
{
    public enum Type { Open, Close, Deposit, Withdrawl, Inquiry, Other }
    public Type TransactionType { get; }
    public string Description { get; }
    public DateTime Timestamp { get; }

    public Transaction(Type transactionType, string description)
    {
        TransactionType = transactionType;
        Description = description;
        Timestamp = DateTime.Now;
    }

    public override string ToString()
    {
        return $"{Timestamp}: {TransactionType} - {Description}";
    }
}

public class Account
{
    public enum Type { Checking, Savings }
    public Type AccountType { get; }
    public int Id { get; }
    public List<Transaction> Transactions { get; private set; }

    private static readonly object IdLock = new object();
    private static int _lastAccountId;

    private readonly object balanceLock = new object();
    private decimal balance;

    public Account(decimal initialDeposit, Type accountType)
    {
        if (initialDeposit < 0)
        {
            throw new ArgumentOutOfRangeException("initialDeposit cannot be negative");
        }

        AccountType = accountType;
        balance = initialDeposit;

        lock (IdLock)
        {
            Id = ++_lastAccountId;
        }

        AddTransaction(Transaction.Type.Open, 
            $"{AccountType} account Id {Id} created with a deposit of: {balance:C}.");
    }

    public void Deposit(decimal amount)
    {
        if (amount < 0)
        {
            throw new ArgumentOutOfRangeException("Deposit amount cannot be negative");
        }

        lock (balanceLock)
        {
            balance += amount;
            AddTransaction(Transaction.Type.Deposit,
                $"{amount} was deposited. New balance: {balance:C}.");
        }
    }

    public void Withdraw(decimal amount)
    {
        if (amount < 0)
        {
            throw new ArgumentOutOfRangeException("Withdrawl amount cannot be negative");
        }

        if (amount > balance)
        {
            throw new ArgumentOutOfRangeException(
                "Cannot withdraw more money than the account contains");
        }

        lock (balanceLock)
        {
            balance -= amount;
            AddTransaction(Transaction.Type.Withdrawl,
                $"{amount} was withdrawn. New balance: {balance:C}.");
        }
    }

    public decimal GetBalance()
    {
        lock (balanceLock)
        {
            AddTransaction(Transaction.Type.Inquiry,
                $"Balance inquiry made. Balance: {balance:C}.");
            return balance;
        }
    }

    private void AddTransaction(Transaction.Type transactionType, string description)
    {
        if (Transactions == null) Transactions = new List<Transaction>();
        Transactions.Add(new Transaction(transactionType, description));
    }
}

输出

enter image description here