how to sum values of duplicate element in array - c#

I have two arrays:
string[] fruit = { "apple", "banana", "lemon", "apple", "lemon" };
int[] quantity = { 2, 4, 1, 2, 2 };
The second one has the same length of the first one, and the integer numbers are the quantity of each fruit.
I want to create these two arrays:
totalefruit = { "apple", "banana", "lemon" };
totalquantity = {4, 4, 3}

Try this:
string[] fruit = { "apple", "banana", "lemon", "apple", "lemon" };
int[] quantity = { 2, 4, 1, 2, 2 };
var result =
fruit
.Zip(quantity, (f, q) => new { f, q })
.GroupBy(x => x.f, x => x.q)
.Select(x => new { Fruit = x.Key, Quantity = x.Sum() })
.ToArray();
var totalefruit = result.Select(x => x.Fruit).ToArray();
var totalquantity = result.Select(x => x.Quantity).ToArray();
result looks like this:

You could use Zip and a lookup:
var fruitQuantityLookup = fruit
.Zip(quantity, (f, q) => new { Fruit = f, Quantity = q })
.ToLookup(x => x.Fruit, x => x.Quantity);
string[] totalefruit = fruitQuantityLookup.Select(fq => fq.Key).ToArray();
int[] totalquantity = fruitQuantityLookup.Select(fq => fq.Sum()).ToArray();

Related

C# function for finding most repeated numbers in an array

Hi I am trying to write a C# (Visual Studio) program for a function that takes integers in an array , and returns an array of integers that contains those integers which are most common in the input array.
sample in out -
[1,2,3,4,3,3,2,2,4] result = [2,3]
[1, 2, 3, 4, 5, 1, 6, 7, 1, 1] result = [1]
[1, 2, 3, 4, 5, 6, 7] result = [1, 2, 3, 4, 5, 6, 7]
I am almost there, but not getting expected results. Below is the code I wrote and I am a beginner.
namespace StringCommonElements
{
class Program
{
static void Main(string[] args)
{
// Compute frequencies for this data.
string[] values = { "bird", "cat", "bird", "dog", "bird", "man", "frog", "cat" };
// Get a list.
List<string> valuesList = new List<string>(values);
// Call our methods.
var freqs = GetFrequencies(valuesList);
DisplaySortedFrequencies(freqs);
}
static Dictionary<string, int> GetFrequencies(List<string> values)
{
var result = new Dictionary<string, int>();
foreach (string value in values)
{
if (result.TryGetValue(value, out int count))
{
// Increase existing value.
result[value] = count + 1;
}
else
{
// New value, set to 1.
result.Add(value, 1);
}
}
// Return the dictionary.
return result;
}
static void DisplaySortedFrequencies(Dictionary<string, int> frequencies)
{
// Order pairs in dictionary from high to low frequency.
var sorted = from pair in frequencies
orderby pair.Value descending
select pair;
// Display all results in order.
foreach (var pair in sorted)
{
Console.WriteLine($"{pair.Key} = {pair.Value}");
}
}
}
}
Here's how you can do that with Linq. That will group the numbers and find the count of each, then take all the ones that show up more than once. Then if the result is empty just return the original array because all the numbers are unique.
public int[] MostCommon(int[] numbers)
{
var ans = numbers
.GroupBy(x => x)
.Select(x => new {x.Key, x.Count}))
.Where(x => x.Count > 1)
.Select(x => x.Key)
.ToArray();
return ans.Length > 0 ? ans : numbers;
}
In case you were just wondering how to make your existing code work, all you have to do is return (or output) the items that have the same frequency as the one with the maximum frequency.
For example:
var maxFrequency = sorted.First().Value;
Console.WriteLine("These items all occur the most:");
foreach (var pair in sorted)
{
if (pair.Value < maxFrequency) break;
Console.WriteLine($" - {pair.Key} = {pair.Value}");
}
To get the single most occurring number, you can use this LINQ expression (this will return 3, even though 2 appears just as much):
int appearsMost = new int[] { 1, 2, 3, 4, 3, 3, 2, 2, 4 }
.GroupBy(x => x)
.Select(x => (Key: x.Key, Items: x.ToList()))
.OrderByDescending(x => x.Items.Count)
.First().Key;
The select clause with the ToList() in between is to prevent having to count() the grouped items multiple times.
The following solution should give you the numbers that appear most. (this will return 2 and 3)
int[] appearMost = new int[] { 1, 2, 3, 4, 3, 3, 2, 2, 4 }
.GroupBy(x => x)
.Select(x => (Key: x.Key, Items: x.ToList()))
.GroupBy(x => x.Items.Count)
.OrderByDescending(x => x.Key)
.First()
.Select(x => x.Key)
.ToArray();
If you want all numbers that appear more than once: (this will return 2,3,4,1)
int[] appearMoreThanOnce = new int[] { 1, 2, 3, 4, 3, 3, 2, 2, 4 }
.GroupBy(x => x)
.Select(x => (Key: x.Key, Items: x.ToList()))
.OrderByDescending(x => x.Items.Count)
.Where(x => x.Items.Count >= 1).Select(x => x.Key).ToArray();
In all cases, you can do the same by animals directly (only with small adjustments):
string[] animalsThatAppearMoreThanOnce = new string[] { "bird", "cat", "bird", "dog", "bird", "man", "frog", "cat" }
.GroupBy(x => x)
.OrderByDescending(x => x.Count())
.Where(x => x.Count() >= 1).Select(x => x.Key).ToArray();
// I added another cat, so this will return 'bird' and 'cat'.
string[] animalsThatAppearMost = new string[] { "bird", "cat", "bird", "dog", "bird", "man", "frog", "cat", "cat" }
.GroupBy(x => x)
.Select(x => (Key: x.Key, Items: x.ToList()))
.GroupBy(x => x.Items.Count)
.First()
.Select(x => x.Key)
.ToArray();
Actually, your methods work. I think it is just a matter of display. In order to emulate the examples that you posted, I would just write the DisplaySortedFrequencies this way:
static void DisplaySortedFrequencies(Dictionary<string, int> frequencies)
{
// Order pairs in dictionary from high to low frequency.
var sorted = from pair in frequencies
orderby pair.Value descending
select pair;
// Display all results in order.
int MaxNumValues = sorted.First().Value;
foreach (var pair in sorted)
{
int numValues = pair.Value;
if (numValues < MaxNumValues) //Show only the most predominant groups
break;
Console.WriteLine($"{pair.Key} = {numValues}");
}
}
In any case, if it is code that has to be performant, I would go for the solutions already posted that use Linq. I you don't want to use Linq for some reason, I would suggest to sort the items first and then count equal elements in a row instead of using a dictionary search for every element.
I have made a few changes to your code.
static void Main(string[] args)
{
// Compute frequencies for this data.
string[] values = { "bird", "cat", "bird", "dog", "bird", "man", "frog", "cat" };
var freqs = GetFrequencies(values);
DisplaySortedFrequencies(freqs);
}
static Dictionary<string, int> GetFrequencies(IEnumerable<string> values)
{
if (values == null) return new Dictionary<string, int>();
var maxCount = 1;
var result = new Dictionary<string, int>();
foreach (string value in values)
{
if (result.TryGetValue(value, out int count))
{
result[value] = count + 1;
if (maxCount < result[value])
{
maxCount = result[value];
}
}
else
{
result.Add(value, 1);
}
}
return result
.Where(item => item.Value == maxCount)
.OrderBy(item => item.Key)
.ToDictionary(item => item.Key, item => item.Value);
}
static void DisplaySortedFrequencies(Dictionary<string, int> frequencies)
{
foreach (var pair in frequencies)
{
Console.WriteLine($"{pair.Key} = {pair.Value}");
}
}

Group with inside an array element using LINQ

For example:
var a = new { Key = new[] {1, 2} ... };
var b = new { Key = new[] {2, 3} ... };
var c = new { Key = new[] {3} ... };
I want a LINQ query that will get the result below, after new [] {a, b, c}.GroupByWithArray(x => x.Key)
Key 1: a
Key 2: a, b
Key 3: b, c
var a = new { Key = new[] { 1, 2 }};
var b = new { Key = new[] { 2, 3 }};
var c = new { Key = new[] { 3 }};
var result =
new[] { a, b, c }.SelectMany(item => item.Key.Select(key => (Item: item, Key: key)))
.GroupBy(pair => pair.Key)
.ToDictionary(group => group.Key,
group => group.Select(pair => pair.Item).ToArray());
var expected = new Dictionary<int, object[]>
{
{ 1, new[] { a }},
{ 2, new[] { a, b }},
{ 3, new[] { b, c }}
};
result.Should().BeEquivalentTo(expected); // Pass Ok
This seems the most logical to what you want:
var a = new { Key = new[] { 1, 2 } };
var b = new { Key = new[] { 2, 3 } };
var c = new { Key = new[] { 3 } };
var values = new[] { 'a', 'b', 'c' };
var result =
new[] { a, b, c }
.Zip(values, (keys, value) => new { keys, value })
.SelectMany(x => x.keys.Key, (x, key) => new { key, x.value })
.GroupBy(x => x.key, x => x.value);
var output =
String.Join(
Environment.NewLine,
result.Select(r => $"Key {r.Key}: {String.Join(", ", r)}"));
That gives:
Key 1: a
Key 2: a, b
Key 3: b, c
Now, I don't know what you meant by the ... in your question, but if I just assume you meant that the list can be longer, then that doesn't change anything.

Two arrays into one Dictionary

I would like to create a
Dictionary<string, int[]> dict
out of two arrays:
string[] keys = { "A", "B", "A", "D" };
int[] values = { 1, 2, 5, 2 };
the result:
["A"] = {1,5}
["B"] = {2}
["D"] = {2}
Is there a way i can do this with LINQ?
I have read about Zip but I don't think I can use since I need to add values to an existing key.value array.
Use .Zip to bind the two collections together and then GroupBy to group the keys.
string[] keys = { "A", "B", "A", "D" };
int[] values = { 1, 2, 5, 2 };
var result = keys.Zip(values, (k, v) => new { k, v })
.GroupBy(item => item.k, selection => selection.v)
.ToDictionary(key => key.Key, value => value.ToArray());
Then to add these items into the dictionary that you already have:
I changed the int[] to List<int> so it is easier to handle Add/AddRange
Dictionary<string, List<int>> existingDictionary = new Dictionary<string, List<int>>();
foreach (var item in result)
{
if (existingDictionary.ContainsKey(item.Key))
existingDictionary[item.Key].AddRange(item.Value);
else
existingDictionary.Add(item.Key, item.Value.ToList());
}
Linq solution:
string[] keys = { "A", "B", "A", "D" };
int[] values = { 1, 2, 5, 2 };
Dictionary<string, int[]> dict = keys
.Zip(values, (k, v) => new {
key = k,
value = v })
.GroupBy(pair => pair.key, pair => pair.value)
.ToDictionary(chunk => chunk.Key,
chunk => chunk.ToArray());
Test:
string report = String.Join(Environment.NewLine, dict
.Select(pair => $"{pair.Key} [{string.Join(", ", pair.Value)}]"));
Console.Write(report);
Outcome:
A [1, 5]
B [2]
D [2]
Try this :
string[] keys = { "A", "B", "A", "D" };
int[] values = { 1, 2, 5, 2 };
Dictionary<string, int[]> dict = keys.Select((x, i) => new { key = x, value = values[i] }).GroupBy(x => x.key, y => y.value).ToDictionary(x => x.Key, y => y.ToArray());

Linq group of chains

This is my collection
var list1 = new List<string> { "aa", "bb", "cc", "dd", "ee" }
.Select(x => new Pair { PropName = x, TypeName = x + "Prop1" })
.ToList();
var list2 = new List<string> { "aa", "bb2", "cc", "dd", "ee" }
.Select(x => new Pair { PropName = x, TypeName = x + "Prop2" })
.ToList();
var list3 = new List<string> { "aa", "bb", "cc", "dd" }
.Select(x => new Pair { PropName = x, TypeName = x + "Prop3" })
.ToList();
var list4 = new List<string> { "aa" }
.Select(x => new Pair { PropName = x, TypeName = x + "Prop4" })
.ToList();
var list5 = new List<string> { "aa", "bb", "bb5", "cc5" }
.Select(x => new Pair { PropName = x, TypeName = x + "Prop5" })
.ToList();
var collection = new List<List<Pair>> { list1, list2, list3, list4, list5 };
It represents some hierarcys (i.e. "aa" is father for "bb")
I want to make something like tree with "Pair" objects. It should have structure like on picture. But with Pair objects. And I do not have any Idea how to do that.

what is the way to declare function like php array_count_values in c#?

i want to declare function in c# that accept an array an
return the Counts all the values of this array
like array_count_values in php
$array = array(1, 1, 2, 3, 3, 5 );
return
Array
(
[1] => 2
[2] => 1
[3] => 2
[5] => 1
)
what is the efficient way to do this ?
thanks
int[] array = new[] { 1, 1, 2, 3, 3, 5 };
var counts = array.GroupBy(x => x)
.Select(g => new { Value = g.Key, Count = g.Count() });
foreach(var count in counts) {
Console.WriteLine("[{0}] => {1}", count.Value, count.Count);
}
Alternatively, you can get a Dictionary<int, int> like so:
int[] array = new[] { 1, 1, 2, 3, 3, 5 };
var counts = array.GroupBy(x => x)
.ToDictionary(g => g.Key, g => g.Count());
Edit
Sorry, I see now that my previous answer was not correct. You are wanting to count each type of unique value.
You can use a Dictionary to store the value types:
object[] myArray = { 1, 1, 2, 3, 3, 5 };
Dictionary<object, int> valueCount = new Dictionary<object, int>();
foreach (object obj in myArray)
{
if (valueCount.ContainsKey(obj))
valueCount[obj]++;
else
valueCount[obj] = 1;
}
If you want to be able to count something besides ints try this
public static Dictionary<dynamic, int> Count(dynamic[] array)
{
Dictionary<dynamic, int> counts = new Dictionary<dynamic, int>();
foreach(var item in array) {
if (!counts.ContainsKey(item)) {
counts.Add(item, 1);
} else {
counts[item]++;
}
}
return counts;
}

Categories