У меня есть массив moviesRented
, в котором хранятся следующие значения:
17 3 3 2 2 2 1 1 1 1
. Значения были прочитаны из проанализированных данных в текстовом файле.
Мне нужно распечатать количество каждого значения. Например, вывод должен быть:
4 появления из 1
3 появления из 2
2 появления из 3
1 появление из 17
Вот мой текущий код:
StreamReader inFile = new StreamReader("project-files/transactions.txt");
string line = inFile.ReadLine();
while(line != null){
string[] temp = line.Split("#");
moviesRented[count] = int.Parse(temp[2]);
count++;
line = inFile.ReadLine();
}
inFile.Close();
for(int i = 0; i < count - 1; i++){
for(int j = i + 1; j < count; j++){
if (moviesRented[i] < moviesRented[j]){
int temp = moviesRented[i];
moviesRented[i] = moviesRented[j];
moviesRented[j] = temp;
}
}
}
// output sorted array
for(int i = 0; i < count; i++){
Console.WriteLine(moviesRented[i]);
}
Я могу получить необходимые значения из текстового файла (они хранятся в массиве moviesRented
), а также отсортировать их от большего к меньшему.
Вот результат moviesRented
после сортировки:
17
3
3
2
2
2
1
1
1
1
Как мне подсчитать значения? Я попробовал что-то вроде этого:
StreamReader inFile = new StreamReader("project-files/transactions.txt");
string line = inFile.ReadLine();
while(line != null){
string[] temp = line.Split("#");
moviesRented[count] = int.Parse(temp[2]);
count++;
line = inFile.ReadLine();
}
inFile.Close();
for(int i = 0; i < count - 1; i++){
int tempCount = 0;
for(int j = i + 1; j < count; j++){
if (moviesRented[i] < moviesRented[j]){
int temp = moviesRented[i];
moviesRented[i] = moviesRented[j];
moviesRented[j] = temp;
}
// this is new compared to the code above
// it compares iteration with next iteration
// and if they match then add 1 to tempCount
if (moviesRented[i] == moviesRented[j]){
tempCount++;
}
}
Console.WriteLine($"{moviesRented[i]} {tempCount}");
}
Это считается, но экземпляров каждого значения слишком много — вот результат с приведенным выше кодом:
17 1
3 1
3 2
2 2
2 1
2 3
1 3
1 2
1 1
Но мне нужно САМОЕ ВЫСОКОЕ значение вхождения каждого слова, а не все, как в приведенном выше выводе.
Как бы я отобразил (вывел на консоль) каждое значение moviesRented
и сколько раз оно встречается в порядке убывания, например, как первый вывод, упомянутый выше:
4 появления из 1
3 появления из 2
2 появления из 3
1 появление из 17
Самый простой способ — использовать LINQ:
var statistics = from x in moviesRented
group x by x into g
select new { Number = g.Key, Count = g.Count() };
foreach(var statItem in statistics)
Console.WriteLine($"{statItem.Count} occurence(s) of {statItem.Number}");
Известный классический алгоритм заключается в использовании словаря (хеш-таблицы), который содержит увеличенное количество каждого значения.
Вы можете сделать это, просто используя Linq:
int[] moviesRented = [17, 3, 3, 2, 2, 2, 1, 1, 1, 1];
var counts = new Dictionary<int, int>();
foreach(var item in moviesRented)
{
// Count the occurences
var count = moviesRented.Count(i => i == item);
counts[item] = count;
}
// Order by occurences
var ordered = counts.OrderByDescending(v => v.Value);
foreach(var item in ordered)
{
Console.WriteLine($"{item.Value} occurrence of {item.Key}");
}
Выход:
4 occurrence of 1
3 occurrence of 2
2 occurrence of 3
1 occurrence of 17
Рабочий пример можно найти здесь
Сортировка по наиболее встречающимся...
int[] moviesRented = [17, 3, 3, 2, 2, 2, 1, 1, 1, 1];
IEnumerable<(int key, int count)> counts = moviesRented
.GroupBy(i => i, (key, items) => (key, items.Count()));
foreach (var tpl in counts.OrderByDescending(t => t.count))
Console.WriteLine("{0} occurences(s) of {1}", tpl.count, tpl.key);
Вот еще один вариант LINQ.
.
int[] moviesRented = { 17, 3, 3, 2, 2, 2, 1, 1, 1, 1 };
var counts = moviesRented.GroupBy(i => i)
.ToDictionary(g => g.Key, g =>g.Count())
.OrderByDescending(kv => kv.Value);
foreach (var item in counts)
{
Console.WriteLine($"{item.Value} occurrence(s) of {item.Key}");
}
Это очень помогло!