循环列表空元素

时间:2016-09-10 18:30:55

标签: c# linq list class

我有一个包含类(People)实例的列表。随着时间的推移,有些人会消失(列表中为空),其他人则添加。然后我想循环遍历非空元素列表。

下面的代码完成了这项工作,但我觉得它写得很糟糕。

  1. 我有一个包含许多null元素的列表。这甚至是个问题吗?凭借他目前的代码,它是可管理的。但是,如果我将createPerson(10);更改为createPerson(300);,将for (int i = 1; i <= 100; i++)更改为for (int i = 1; i <= 1000; i++),则我的列表将包含~6300个元素,其中6000个为空。

  2. 逐个元素地检查列表并检查if (person[i] != null)似乎很愚蠢。还有其他办法吗?应该在这里使用LINQ吗?

  3. 我想也许最好删除null元素,并将带有数据的元素移动到null元素。然后我需要使用person.Id(唯一的增量ID)而不是索引号来标识元素。类似于:

    var item = person.First(i => i.Id == Id);
    

    是否有针对此问题的推荐方法?

    代码

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace listID
    {
        class Program
        {
            static List<People> person = new List<People>();
            static Random rnd = new Random();
    
            static void Main(string[] args)
            {
                // Generates 10 people of random ages.
                createPerson(10);
    
                // Advances 100 years.
                for (int i = 1; i <= 100; i++)
                {
                    circleOfLife();
                }
    
                writeList();
                Console.ReadKey();
            }
    
            /// <summary>
            /// Writes out the current elements in the list
            /// </summary>
            static void writeList()
            {
                for (int i = 0; i < person.Count; i++)
                {
                    if (person[i] != null)
                        Console.WriteLine("List index: " + i + " -  " + person[i].age + " years old.");
                }
            }
    
    
            /// <summary>
            /// Creates people of random age between 0 and 100.
            /// </summary>
            /// <param name="q">Amount of people to create</param>
            static void createPerson(int q)
            {
                for (int i = 1; i <= q; i++)
                {
                    People newPerson = new People();
                    newPerson.age = rnd.Next(100);
                    person.Add(newPerson);
                }
            }
    
            /// <summary>
            /// Increases age of person by a year. If person reaches age of 100, they get removed, and another one of random age is added.
            /// </summary>
            static void circleOfLife()
            {
                for (int i = 0; i < person.Count; i++)
                {
                    if(person[i] != null)
                    {
                        person[i].increaseAge();
                        if (person[i].age > 99)
                        {
                            person[i] = null;
                            createPerson(1);
                        }
                    }
                }
            }
    
        }
    
        class People
        {
            public int age;
    
            private static int m_Counter = 0;
            public int Id { get; set; }
            public People()
            {
                this.Id = System.Threading.Interlocked.Increment(ref m_Counter); // Gives unique incrememntal ID number to each elelment.
            }
    
            public void increaseAge()
            {
                age++;
            }
    
        }
    }
    

    输出:

    List index: 13 -  93 years old.
    List index: 17 -  26 years old.
    List index: 18 -  95 years old.
    List index: 19 -  45 years old.
    List index: 20 -  34 years old.
    List index: 21 -  92 years old.
    List index: 22 -  58 years old.
    List index: 23 -  44 years old.
    List index: 24 -  67 years old.
    

    非常感谢帮助。我还在学习,所以示例代码非常有用。

5 个答案:

答案 0 :(得分:2)

为什么不替换人而不是分配给null并添加?

 static void circleOfLife() {
   for (int i = 0; i < persons.Count; ++i) {
     persons[i].increaseAge();

     // if a person is too old  
     if (persons[i].age > 99) {
       // ...generate a new person and put it on old person's place
       persons[i] = new People() {
         age = rnd.Next(100)
       }; 
     }
   } 
 }

在这种情况下,您将摆脱讨厌的null检查。

答案 1 :(得分:1)

您的列表是否应包含null个人对象的Age > 99值取决于您希望在域模型中表达的内容。

但我无法想象为什么要在列表中保留null值。零值的存在传达了哪些附加信息。关于这些人是谁的信息&#34;丢失了,因为id已经与它的实例一起消失了。如果你想跟踪有多少人一直存在,那么一个简单的计数器就足够了。因此,这些null值只会导致列表不断增加,并且会随着时间的推移而降低性能。

如果你想跟踪他们的ID太老的人实例&#34;那么你可以使用&#34;生活人员和#34;和一个存储历史实例的列表。

一些有用的LINQ表达式作为例子:

var livingPeople = people.Where(p => p != null && p.Age <= 99);
people.RemoveAll(p => p == null); // removes all null values
var numberOfPassedPeople = people.Count(p => p == null);

答案 2 :(得分:0)

我建议使用RemoveAll从列表中删除元素。

static void circleOfLife()
{
    for (int i = 0; i < person.Count; i++)
    {
        if(person[i] != null)
        {
            person[i].increaseAge();
        }
    }
    //Select all id of person having Age > 99
    var personIds = person.Where(p => p.Age > 99).Select(p => p.Id);
    person.RemoveAll(p => p.Age > 99); //or person.RemoveAll(p => personIds.Contains(p.Id));
    createPerson(personIds.Count());
}

它将选择所有具有Age&gt;的人99然后将其从列表中删除。

答案 3 :(得分:0)

您可以使用LINQ Where()扩展方法,只获取非空的方法,如

var item = person.Where(p => p != null);

答案 4 :(得分:0)

您还可以使用Lookup

var lookup = person.Where(p => p != null && p.Age <= 99).ToLookup(p => p.Id);    
var item = lookup[42].FirstOrDefault(); // null if no person with Id 42