在列表<>中找到特定索引处的项目的最有效方法,修改项目然后更新列表<>?

时间:2010-07-07 12:16:13

标签: c# collections

选择List<Car>。每个Car都有一个标识它的唯一索引,比如RegNumber,然后是另一个描述它的属性 - 比如说Color

我想

  1. 检查该系列是否包含RegNumber 5
  2. 的汽车
  3. 如果是,请更改颜色
  4. 如果没有,请为该车添加新项目
  5. 保存列表
  6. 这就是我目前正在这样做的方式,我在问是否有更好,更有效的方式来做这件事?

    Car car = CarsForSale.Find(c => c.RegNumber == 5);
    
    if (car != null)
    {
       foreach (Car car in CarsForSale)
       {
          if (car.RegNumber == 5)
          {
             car.Color = "Red";
             break;
          }
       }
    }
    else
    {
       CarsForSale.Add(new Car(5, "Red"));
    }
    
    Save(CarsForSale);
    

    修改 没有多辆汽车具有相同的reg - RegNumber是问题中所述的唯一。

    这真的只是一个愚蠢的@ ss时刻,无论如何代码审查都会发现。感谢所有回复,并且没有嘲笑我明显的stoopid问题。当然,从集合返回的item /元素是一个引用,所以绝对没有必要再次遍历列表...我想我的头撞墙。

5 个答案:

答案 0 :(得分:4)

首先,您不需要在循环中对car.RegNumber == 5进行测试 - 您已经从声明中找到了第一辆符合此标准的汽车:

Car car = CarsForSale.Find(c => c.RegNumber == 5);

事实上,你的整个循环是多余的,你可以拥有:

if (car != null)
{
    car.Color = "Red";
}
else
{
    CarsForSale.Add(new Car(5, "Red"));
}

除非您想要找到RegNumber等于5的所有车辆,否则您的第一行不正确,因为它只会找到符合条件的第一辆车。要找到你想要的所有汽车:

var cars = CarsForSale.Where(c => c.RegNumber == 5);

foreach (Car car in cars)
{
    car.Color = "Red";
}

if (!car.Any())
{
    CarsForSale.Add(new Car(5, "Red"));
}

使用原始代码,编译器应警告您,循环中car的重新定义会隐藏原始定义(我引用的那个)。

答案 1 :(得分:2)

为什么在已经有结果的情况下重新遍历列表?

这将取得同样的结果:

Car car = CarsForSale.Find(c => c.RegNumber == 5);
if (car != null)
{
   car.Color = "Red";
}
else
{
   CarsForSale.Add(new Car(5, "Red"));
}
Save(CarsForSale);

Find CarsForSale方法的结果(如果返回结果)将是引用类型,这意味着对car的任何更改都将更改{{1}中的项目也是。我猜你认为CarsForSale的结果会与Find中的实际项目断开连接,因此不必要的foreach循环?

答案 2 :(得分:2)

一旦你从LINQ声明中找到了你正在寻找的汽车,就没有必要回过头去查找匹配项了:

Car car = CarsForSale.Where(c => c.RegNumber == 5).FirstOrDefault();

if(car != null)
{
    car.Color = "Red";
}
else
{
    CarsForSale.Add(new Car(5, "Red"));
}

Save(CarsForSale);

或者如果有多辆具有相同RegNumber的汽车:

var cars = CarsForSale.Where(c => c.RegNumber == 5);

if(cars.Any())
{
    foreach(Car car in cars)
        car.Color = "Red";
}
else
{
    CarsForSale.Add(new Car(5, "Red"));
}

Save(CarsForSale);

答案 3 :(得分:2)

更新

在回应此评论时,您还有其他几个答案:

  

如果有几辆车怎么办?   RegNumber为5?

如果多辆汽车可能具有相同的RegNumber,则调用Find不是正确的方法。 Find只是枚举列表以查找匹配项;你最好不要跳过它并保持foreach循环。

但是,您可以使用Where来简化您的代码:

var matches = CarsForSale.Where(c => c.RegNumber == 5);
int numMatches = 0;

foreach (Car match in matches )
{
    match.Color = "Red";
    ++numMatches;
}
if (numMatches == 0)
{
   CarsForSale.Add(new Car(5, "Red"));
}

原始答案

整个foreach循环是多余的:您基本上通过调用Find完成了相同的工作。

所以代码可以简化:

Car car = CarsForSale.Find(c => c.RegNumber == 5);

if (car != null)
{
    car.Color = "Red";
}
else
{
   CarsForSale.Add(new Car(5, "Red"));
}

也就是说,如果您在List<Car> RegNumber之前查找汽车,那么使用Dictionary<int, Car>代替List<Car>是有意义的:

Car car;
if (CarsForSale.TryGetValue(5, out car))
{
    car.Color = "Red";
}
else
{
    CarsForSale[5] = car = new Car(5, "Red");
}

答案 4 :(得分:1)

正如Dan已经提到的,如果你有一个独特的属性,你应该将它作为Dictionary<TKey, TValue>中的一个键。

因为检查某些内容是否在一个字典中是一个O(1)操作,而在一个列表中它是最坏情况下的O(n)(现在想象你的列表中有100万辆汽车)。

var carsForSale = new Dictionary<int, Car>();

//Create a car which you like to check
var checkCar = new Car(4, Color.Red);

//Use this approach if you want to change only a few properties
//of an existing item
if (carsForSale.ContainsKey(checkCar.RegNum))
{
    carsForSale[checkCar.RegNum].Color = checkCar.Color;
}
else
{
    carsForSale[4] = checkCar;
}

//If you have to take over ALL property settings, you can also
//forget the old item and take the new one.
//The index operator is smart enough to just add a new one
//or to delete an old and add the new in one step.
carsForSale[checkCar.RegNum] = checkCar;

汽车类的虚拟实现:

public class Car
{
    public int RegNum { get; private set; }
    public Color Color { get; set; }

    public Car(int regNum)
        : this(regNum, Color.Empty)
    { }

    public Car(int regNum, Color color)
    {
        RegNum = regNum;
        Color = color;
    }
}

问题您使用词典的原因是,因为您想要明确告诉键是什么(汽车的RegNum属性),但您也可以使用Hashset<T>如果您的Car对象能够正确实现Equals()GetHashCode(),但这比您想象的要复杂一些。可以在Essentials C#一书中找到一个很好的解释。