【问题标题】:Update item in IEnumerable更新 IEnumerable 中的项目
【发布时间】:2015-04-16 13:28:28
【问题描述】:

我需要更新 IEnumerable 列表中的值。

这是一个简短的 IEnumerable 示例:

IEnumerable<string> allsubdirs = new List<string>() { "a", "b", "c" };

现在,如果我想为每个项目添加时间戳,这不起作用:

allsubdirs.Select(a => a = a + "_" + DateTime.Now.ToString("hhmmss")).ToList();

这也不行:

foreach (var item in allsubdirs)
            item = item + "_" + DateTime.Now.ToString("hhmmss");

我让它像这样工作:

IEnumerable<string> newallsubdirs = allsubdirs.Select(a => a + "_" + DateTime.Now.ToString("hhmmss")).ToList();
        allsubdirs = newallsubdirs;

但这在某种程度上似乎是作弊。请问这样做的正确方法是什么?

【问题讨论】:

  • IEnumerable只读。你不能修改它。如果要修改collection,可以考虑改成List
  • 或许使用 List 会更合适?
  • 使用适当的类而不是字符串,即使是 Tuple 或 Tuple 也可以。迭代查询结果并将第二项设置为时间戳
  • @PanagiotisKanavos - 从变量名称来看,他们试图将日期时间附加到文件夹名称
  • @Sayse 那么 OP 在Select 之后已经有了正确的结果,但是因为它们从未存储过而将它们丢弃

标签: c# linq


【解决方案1】:

Linq 用于查询,而不是更新。 Linq 查询根据投影、过滤器等返回一个 集合。因此您的选择是:

  • 将“新”集合保存回变量(或新变量,如有必要):

    allsubdirs = allsubdirs.Select(a => a = a + "_" + DateTime.Now.ToString("hhmmss")).ToList();
    
  • 使用像IList&lt;T&gt;这样的可写接口和for循环:

    IList<string> allsubdirs = new List<string>() { "a", "b", "c" };
    
    for(int i=0; i<allsubdirs.Count(); i++)
        allsubdirs[i] = allsubdirs[i] + "_" + DateTime.Now.ToString("hhmmss");
    

主要区别在于Select 不会修改原始集合,而for 循环会。

我的意见是Select 更干净,不是“作弊”——你只是在原始集合之上添加了一个投影。

【讨论】:

    【解决方案2】:

    D Stanley 已正确回答。我想补充他的答案,因为标题是Update item in IEnumerable,这意味着只有一个项目要更新。

    正如D Stanely 在他的answer 中解释的那样:

    Linq 用于查询,而不是更新。

    使用 IList 和 for 循环等可写接口

    对于更新单个项目,您可以检索要更新的项目的索引并使用该索引来更新它。

    例如:

    IList<string> allsubdirs = new List<string>() { "a", "b", "c" };
    int index = allsubdirs.IndexOf("a");
    allsubdirs[index] = "d";
    

    【讨论】:

      【解决方案3】:

      你的第一次尝试

      allsubdirs.Select(a => a = a + "_" + DateTime.Now.ToString("hhmmss")).ToList();
      

      返回一个新的IEnumerable,但不改变旧的。对于那个用途

      allsubdirs = allsubdirs.Select(a => a + "_" + DateTime.Now.ToString("hhmmss")).ToList();
      

      【讨论】:

      • 或者简单地将结果存储在另一个变量中。它不必替换原来的,它使代码更干净
      • 作业不应该在这里做;它实际上并没有做任何事情,但它给人一种错误的印象,因此 OP 的混乱。
      • @Servy:实际上我认为这为我清除了它!谢谢
      • @PanagiotisKanavos 好吧,如果这是在方法内部执行并且调用者希望修改参数,则替换变量是正确的
      • @JimAho 但参数 不会 被修改。除非它是 refout 并且代码替换了 参数本身,而不是变量。
      【解决方案4】:

      试试这个:-

      var result= allsubdirs.Select(x => String.Format("{0}_{1}", x,
                                            DateTime.Now.ToString("hhmmss")));
      

      如果您不想将其存储在另一个变量中,请考虑使用ToList()

      【讨论】:

        【解决方案5】:

        如现有答案中所述,IEnumerable 集合不能通过尝试为其元素之一分配新值来修改。

        但是,如果集合中包含的元素是可变类型,您可以修改它们。但是对于您的示例,这是不可能的,因为 string 是不可变的。

        所以如果要修改IEnumerable中已有的元素,元素本身应该是支持修改操作的类型,如下例所示。

        public class MyItem
        {
            private string _value;
        
            public MyItem(string content)
            {
                _value = content;
            }
            public void Append(string other)
            {
                _value += other;
            }
            public void ReplaceWith(Func<string, string> replacer)
            {
                _value = replacer(_value); 
            }
        }
        

        那么你可以像这样使用它:

        IEnumerable<MyItem> allsubdirs = new List<MyItem>() { new MyItem("a"), new MyItem("b"), new MyItem("c") };
        
        foreach (var item in allsubdirs)
                item.Append("_" + DateTime.Now.ToString("hhmmss"));
        

        【讨论】:

          猜你喜欢
          • 2020-02-20
          • 1970-01-01
          • 2016-06-25
          • 1970-01-01
          • 2012-02-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-11-07
          相关资源
          最近更新 更多