【问题标题】:Generate unique list variable生成唯一列表变量
【发布时间】:2016-03-09 13:26:56
【问题描述】:

我有一个 C# 程序,其中有一个唯一字符串列表 (List<string>)。这些字符串代表不同案例的名称。是什么并不重要。但它们必须是独一无二的。

cases = new List<string> { "case1", "case3", "case4" }

有时我会将一些以文本格式保存的案例读入我的程序中。有时存储在文件中的案例与我程序中的案例名称相同。我必须重命名这个新案例。假设我从文件中加载的案例名称是 case1。

但问题是。如何在不添加大的随机字符串的情况下重命名它。在我的情况下,理想情况下它应该被称为 case2,我没有找到任何可以做到这一点的好的算法。我想找到可以添加的小数,使其独一无二。

【问题讨论】:

  • 我已经测试了所有的解决方案并且都可以正常工作。使用哪种更取决于口味:)

标签: c# string list


【解决方案1】:

我会使用只接受唯一值的HashSet

List<string> cases = new List<string>() { "case1", "case3", "case4" };
HashSet<string> hcases = new HashSet<string>(cases);

string Result = Enumerable.Range(1, 100).Select(x => "case" + x).First(x => hcases.Add(x));
// Result is "case2"

在这个示例中,我尝试将 1 到 100 之间的元素添加到哈希集中并成功确定第一个 Add()

【讨论】:

    【解决方案2】:

    如果您有一个唯一字符串列表,请考虑改用HashSet&lt;string&gt;。由于您想要递增数字,听起来好像您实际上应该使用自定义类而不是string。包含名称和数字属性的一种。然后你可以增加数字,如果你想要全名(或覆盖ToString)使用Name + Number

    假设该类是Case,您可以填写HashSet&lt;Case&gt;HashSet.Add 对重复项返回 false。然后使用一个循环增加数字直到可以添加。

    类似这样的:

    var cases = new HashSet<Case>();
    // fill it ...
    
    // later you want to add one from file:
    while(!cases.Add(caseFromFile))
    {
        // you will get here if the set already contained one with this name+number
        caseFromFile.Number++;
    }
    

    一种可能的实现方式:

    public class Case 
    {
        public string Name { get; set; }
        public int Number { get; set; }
        // other properties
    
        public override string ToString()
        {
            return Name + Number;
        }
        public override bool Equals(object obj)
        {
            Case other = obj as Case;
            if (other == null) return false;
            return other.ToString() == this.ToString();
        }
        public override int GetHashCode()
        {
            return (ToString() ?? "").GetHashCode();
        }
        // other methods
    }
    

    【讨论】:

      【解决方案3】:

      解决方案非常简单。获取当前存储在列表中的最大案例数,加一并添加新值:

      var max = myList.Max(x => Convert.ToInt32(x.Substring("case".Length))) + 1;
      myList.Add("case" + max);
      

      工作fiddle

      编辑:为了填补你收藏中的任何“漏洞”,你可以使用这个:

      var tmp = myList;
      var firstIndex = Convert.ToInt32(myList[0].Substring("case".Length));
      for(int i = firstIndex; i < tmp.Count; i++) {
          var curIndex = Convert.ToInt32(myList[i].Substring("case".Length)); 
          if (curIndex != i) 
          {
              myList.Add("case" + (curIndex + 1));
              break;
          }
      }
      

      它会检查列表中的每个元素,如果它在 case 后面的编号等于它在列表中的索引。循环在条件被破坏的第一个元素处停止,因此您在列表中有一个洞。

      【讨论】:

      • 我认为这是一个足够好的起点,因为它总是会根据列表中的最高值增加 - 加 1
      • 这样做的问题是它会使用下一个最大数字,而不是 2,正如 OP 所说,这在理想情况下是他想要的。
      • 实际上 - 你是对的 sr28 - 刚刚掌握了那个奇怪的细微差别
      • @sr28 现在它也应该填满洞了。
      猜你喜欢
      • 2013-03-31
      • 1970-01-01
      • 1970-01-01
      • 2018-04-15
      • 2019-11-08
      • 2015-01-02
      • 1970-01-01
      • 2013-04-22
      • 2011-07-06
      相关资源
      最近更新 更多