在 List<> 中的某个索引处查找项目、修改该项目然后更新 List<> 的最有效方法?

发布于 2024-09-08 15:36:57 字数 797 浏览 3 评论 0 原文

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

我想

  1. 检查该集合中是否有一辆 RegNumber 5 的汽车(
  2. 如果有),如果没有,则更改颜色
  3. ,为该汽车添加一个新项目,
  4. 保存列表

这是我目前正在执行的方式,我正在询问是否有更好、更有效的方法来做到这一点?

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);

编辑 不存在具有相同注册的多辆汽车 - 正如问题中所述,注册编号是唯一的。

无论如何,这实际上只是一个完全愚蠢的时刻,代码审查会发现。感谢您的所有答复,也感谢您没有嘲笑我明显愚蠢的问题。当然,从集合返回的项目/元素是一个引用,因此绝对不需要再次遍历列表......我想是时候把我的头撞到墙上了。

Take List<Car>. Each Car has a unique index identifying it, say RegNumber and then another property describing it - say Color for example.

I want to

  1. check if the collection has a car with RegNumber 5
  2. if it does, change the color
  3. if it doesn't, add a new item for that car
  4. save the list

This is the way I am currently doing it and I'm asking if there is a better, more efficient way of doing this?

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);

EDIT
There are not multiple cars with the same reg - the RegNumber is unique as stated in the question.

This was really just a total dumb@ss moment here anyway that a code review would have spotted. Thanks for all the replies and for not mocking my clearly stoopid question. Of course the item/element returned from the collection is a reference so there is absolutely no need to iterate through the list again...time to go bang my head against a wall I think.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

暮色兮凉城 2024-09-15 15:36:57

首先,您不需要在循环中测试 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 的重新定义将隐藏原始定义(我引用的那个) 。

Well first off you don't need your test for car.RegNumber == 5 in the loop - you've already found the first car that match this criterion from your statement:

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

In fact your whole loop is redundant, you can just have:

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

Unless you want to find all cars that have RegNumber equal to 5, in which case your first line is incorrect as that will only find the first car that matches the criteria. To find all the cars you want something along these lines:

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"));
}

With your original code the compiler should have warned you that the redefinition of car in the loop would hide the original definition (the one I've quoted).

胡渣熟男 2024-09-15 15:36:57

当你已经有了结果时,为什么还要重新遍历列表呢?

这将实现相同的结果:

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

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

Why are you re-iterating through the list when you already have a result?

This will achieve the same outcome:

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

The result from the Find method of CarsForSale, if it returns a result, will be a reference type, which means any changes to car will change the item in CarsForSale as well. I'm guessing you thought that the result from Find would be disconnected from the actual item in CarsForSale, hence the unnecessary foreach loop?

琴流音 2024-09-15 15:36:57

更新

为了回应此评论,您留下了其他几个答案:

如果有几辆车怎么办?
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 循环是多余的:您基本上正在做与已经完成的相同的工作调用查找

因此代码可以简化:

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

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

也就是说,如果您要通过 RegNumberList 中查找汽车,那么使用 是有意义的字典而不是List

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

Update

In response to this comment you've left on a couple of other answers:

What if there are several cars with
the RegNumber of 5?

If it's possible for multiple cars to have the same RegNumber, then calling Find is not the right approach. Find is just enumerating over the list to find a match; you'd be better off skipping it and keeping your foreach loop.

You could, however, make your code more concise by using Where instead:

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"));
}

Original answer

That whole foreach loop is redundant: you're basically doing the same work you already did by calling Find.

So the code can be simplified:

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

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

That said, if you're looking up cars in your List<Car> by RegNumber, it would make sense to use a Dictionary<int, Car> instead of a List<Car>:

Car car;
if (CarsForSale.TryGetValue(5, out car))
{
    car.Color = "Red";
}
else
{
    CarsForSale[5] = car = new Car(5, "Red");
}
翻了热茶 2024-09-15 15:36:57

一旦您从 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);

Once you have the car you're looking for from the LINQ statement, there's no need to loop back through the collection to find the match:

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

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

Save(CarsForSale);

Or if there are going to be multiple Cars with the same 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);
橘亓 2024-09-15 15:36:57

正如 Dan 已经提到的,如果您有一个独特的属性,您应该将其用作 字典

因为检查字典中是否有某项内容是 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 属性),但您也可以使用 < a href="http://msdn.microsoft.com/en-us/library/bb359438.aspx" rel="nofollow noreferrer">Hashset 如果您的 Car 对象会正确实现 Equals()GetHashCode() 但这比您想象的要复杂一些。可以在Essentials C#一书中找到很好的解释。

So as Dan already mentioned, if you have a unique property you should use it as a key within a Dictionary<TKey, TValue>.

Cause checking if something is within a Dictionary is an O(1) operation, while within a List it is just O(n) in the worst case (and now imagine you have 1 million cars within your list).

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;

Dummy implementation of the car class:

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;
    }
}

The problem why you are using a Dictionary is, cause you want to explicitly tell what the key is (the RegNum property of your car), but you could also use a Hashset<T> if your Car object would correctly implement Equals() and GetHashCode() but this is a little more complex than you might think. A good explanation can be found in the Essentials C# book.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文