按出现次数对字符串行进行排序

3

我还处于学习C#的初级阶段,当我尝试按照文件中字符串出现次数排序时遇到了问题。

以下是我的代码:

string[] listLines = System.IO.File.ReadAllLines(@"F:\VS\AI.xls");

Array.Sort<string>(listLines); // sort alfabeticaly
System.Console.WriteLine("History of experienced feeds:");

/*
foreach (var line in listLines) //loop to return lines in alfabetical order
{
    Console.WriteLine("\t" + line);
}
*/

// counts occurrences
var dict = new Dictionary<string, int>();

foreach (var value in listLines)
{
    if (dict.ContainsKey(value))
        dict[value]++;
    else
        dict[value] = 1;
}

foreach (var pair in dict)
    Console.WriteLine("{1} times {0}", pair.Key, pair.Value);

System.Console.WriteLine("");
System.Console.WriteLine("Press Enter to see most common feeds:");

Console.ReadKey();

/* Finds duplicates and sorts them alphabetically */
System.Console.WriteLine("Most common:");
var duplicates = listLines.GroupBy(i => i) 
                          .Where(g => g.Count() > 1)
                          .Select(g => g.Key);

foreach (var d in duplicates)
    Console.WriteLine(d);

您可以看到,这个问题可以分为两部分。首先,我计算每个字符串出现的次数。然后,我只显示那些出现超过一次的字符串 - 按字母顺序排列。

我需要的是介于两者之间的东西:一种以重复出现的字符串按照出现次数从少到多的顺序显示的方法。

您能指导我实现这个正确的方法吗?

谢谢,

4个回答

2
var strings = new string[] { "a", "a", "b", "b", "b", "c" };
var mostPopular = strings
    .GroupBy(s => s) //removed unnecessary count
    .OrderByDescending(g => g.Count());
mostPopular.ToList().ForEach(g => Console.WriteLine("{0}: {1}", g.Key, g.Count()));

GroupBy 的作用是从 IGrouping<string,string> 中选择三个组。

每个组都包含一个键(我们正在分组的值)和一组字符串(与该键匹配的值)。

一个键是 "a",那么被分组的元素集合是 ["a", "a"],所以 Count 是 2。 另一个键是 "b",那么被分组的元素集合是 ["b", "b", "b"],所以 Count 是 3。

这是一个文字解释,但我认为它让人感到更加复杂和困惑。我更喜欢将其视为类似于

SELECT s, count(*) from strings GROUP BY s ORDER BY count(*) DESC

能够工作!您能否简要地写出这里实际发生了什么?谢谢! - paddy
我从字符串列表开始,然后使用 Linq 的 GroupBy 方法。这将创建一个分组,其中包含一个键(原始字符串)和按该键分组的项目集合。这样我们就可以查看匹配该键的项目数。这大致相当于 SELECT s, count(*) from strings GROUP BY s ORDER BY count(*) DESCENDING - Scott Hannen
非常感谢你,Scott。你的答案完美地解决了我的问题,你的代码正是我所寻找的。谢谢你的解释,我会仔细学习,以便将来能够重新创建这个解决方案。谢谢! - paddy
我从“GroupBy”中删除了一个细节,并用注释标记了它。这是不必要的 - 如果它被删除,你可以看出它不会改变任何东西。 - Scott Hannen

2
Linq来解救:)
new [] { "A", "Be", "D", "C", "Be", "C", "D", "C"}
.GroupBy(v => v)
.Select(g => new { Value = g.Key, Count = g.Count() })
.OrderByDescending(g => g.Count)
.Select(g => g.Value)

提供:

C 
Be 
D 
A 

1
将此添加到您的代码中:

foreach(var str in dict.Where(p => p.Value > 1).OrderBy(p => p.Value).Select(p => p.Key))
  Console.WriteLine(str);

你需要在填充字典后添加这行代码。你的字典已经被填充了吗? - Riad Baghbanli
我认为它是这样的,因为代码的第二部分是有效的。 - paddy
我添加了一个子句,只显示出现次数大于1的字符串。 - Riad Baghbanli

1
foreach(KeyValuePair kvp in dict.Where(x => x.Value > 1) 
                                .OrderByDescending(x => x.Value)) 
      Console.WriteLine(kvp.Key);

我认为你需要添加Where子句以显示出现次数大于1的行。 - Riad Baghbanli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接