使用重复索引后缀修改重复值(使用Linq)

时间:2018-02-15 19:37:14

标签: c# linq

我有一个清单:

List<string> myList = new List<string>{ "dog", "cat", "dog", "bird" };

我希望输出列表:

"dog (1)", "cat", "dog (2)", "bird"

我已经查看了this个问题,但它只讨论重复计数,我的输出应该是重复索引。喜欢 duplicate (index)

我试过这段代码:

var q = list.GroupBy(x => x)
            .Where(y => y.Count()>1)
            .Select(g => new {Value = g.Key + "(" + g.Index + ")"})

但它似乎不起作用,因为:

  1. 需要返回我的所有列表\或者只需修改现有列表。 (我的回答只返回重复的那些)
  2. 对于重复值,需要根据其“重复索引”添加前缀。
  3. 如何在C#中执行此操作?有没有办法使用Linq?

4 个答案:

答案 0 :(得分:2)

接受的解决方案有效,但当列表大小变大时效率极低。

您要做的是首先在高效的数据结构中获取所需的信息。你能实现一个类:

sealed class Counter<T>
{
  public void Add(T item) { }
  public int Count(T item) { }
}

其中Count返回使用该项调用Add的次数(可能为零)。 (提示:你可以使用Dictionary<T, int>效果良好。)

好的。现在我们有了有用的帮助,我们可以:

var c1 = new Counter<string>();
foreach(string item in myList)
  c1.Add(item);

大。现在我们可以通过使用第二个计数器构建我们的新列表:

var result = new List<String>();
var c2 = new Counter<String>();
foreach(string item in myList)
{
  c2.Add(item);
  if (c1.Count(item) == 1))
    result.Add(item);
  else
    result.Add($"{item} ({c2.Count(item)})");
}

我们已经完成了。或者,如果您想要修改列表:

var c2 = new Counter<String>();
// It's a bad practice to mutate a list in a foreach, so
// we'll be sticklers and use a for.
for (int i = 0; i < myList.Count; i = i + 1)
{
  var item = myList[i];
  c2.Add(item);
  if (c1.Count(item) != 1))
    myList[i] = $"{item} ({c2.Count(item)})";
}

这里的教训是:创建一个有用的帮助类,可以很好地解决一个问题,然后使用该帮助程序类使您的实际问题的解决方案更加优雅。你需要计算一些东西来解决问题吗? 制作一个反击类

答案 1 :(得分:1)

执行此操作的一种方法是简单地创建一个新列表,其中包含多次出现的每个项目的附加文本。当我们找到这些项目时,我们可以使用计数器变量创建格式化的字符串,如果格式化字符串列表已包含该计数器,则递增计数器。

请注意,这是 NOT 一个表现良好的解决方案。这是我头脑中的第一件事。但这是一个开始的地方......

private static void Main()
{
    var myList = new List<string> { "dog", "cat", "dog", "bird" };

    var formattedItems = new List<string>();

    foreach (var item in myList)
    {
        if (myList.Count(i => i == item) > 1)
        {
            int counter = 1;
            while (formattedItems.Contains($"{item} ({counter})")) counter++;
            formattedItems.Add($"{item} ({counter})");
        }
        else
        {
            formattedItems.Add(item);
        }
    }

    Console.WriteLine(string.Join(", ", formattedItems));

    Console.Write("\nDone!\nPress any key to exit...");
    Console.ReadKey();
}

<强>输出

enter image description here

答案 2 :(得分:1)

此解决方案在列表大小方面不是二次方,并且它在OP中首选修改列表。

任何有效的解决方案都会涉及预先通过,以便查找和计算重复项。

List<string> myList = new List<string>{ "dog", "cat", "dog", "bird" };

//map out a count of all the duplicate words in dictionary.
var counts = myList
    .GroupBy(s => s)
    .Where(p => p.Count() > 1)
    .ToDictionary(p => p.Key, p => p.Count());

//modify the list, going backwards so we can take advantage of our counts.
for (int i = myList.Count - 1; i >= 0; i--)
{
    string s = myList[i];
    if (counts.ContainsKey(s))
    {
        //add the suffix and decrement the number of duplicates left to tag.
        myList[i] += $" ({counts[s]--})";
    }
}

答案 3 :(得分:1)

好的,@ EricLippert挑战了我,我无法放手。这是我的第二次尝试,我相信它表现更好,并根据要求修改原始列表。基本上我们创建第二个列表,其中包含第一个中的所有重复条目。然后我们向后遍历第一个列表,修改在重复列表中具有对应项的任何条目,并在每次遇到重复列表时从重复列表中删除该项:

*tmp*

<强>输出

enter image description here