循环列表空元素

本文关键字:元素 列表 循环 | 更新日期: 2023-09-27 18:06:25

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

下面的代码可以完成这个工作,但是我觉得它写得很差。

  1. 我有一个列表与许多空元素。这是个问题吗?使用当前的代码,它是可管理的。但是,如果我将createPerson(10);改为createPerson(300);,将for (int i = 1; i <= 100; i++)改为for (int i = 1; i <= 1000; i++),则我的列表将具有~6300个元素的Count,其中6000个为空。

  2. 逐个元素遍历列表并检查if (person[i] != null)似乎很愚蠢。还有别的方法吗?这里应该使用LINQ吗?

我想也许最好删除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.

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

循环列表空元素

你为什么不代替人,而不是分配给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检查。

您的列表是否应该包含具有Age > 99的person对象的null值取决于您想要在域模型中表达的内容。

但是我无法想象为什么在列表中保留null值的好理由。空值的存在传递了什么附加信息?关于"这些人是谁"的信息丢失了,因为id与其实例一起消失了。如果您想要跟踪一直存在的人数,那么一个简单的计数器就足够了。所以这些null值只会导致一个不断增加的列表,并随着时间的推移减慢性能。

如果你想跟踪id为"太老"的人实例,那么你可以使用两个"活着的人"列表和一个存储历史实例的列表。

一些有用的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);

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

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

您也可以使用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

我建议使用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());
}

它将选择所有年龄> 99的人,然后从列表中删除。