I'm trying to console.writeline my answer but I am missing something and after 2 hours of searching, I just can't figure it out.
I want my console to say
Apple Large 2
Apple Mid 1
Apple Small 2
The goal is for it to say the type, the size, group the sizes together, and state how many sizes there are of each Here's my code, any help would be appreciated thanks
namespace AppleGrouping
{
class Program
{
static void Main(string[] args)
{
var buckets = new List<Ap>()
{
new Ap { Type = "Apple", Size = "Large" },
new Ap { Type = "Apple", Size = "Small" },
new Ap { Type = "Apple", Size = "Mid" },
new Ap { Type = "Apple", Size = "Large" },
new Ap { Type = "Apple", Size = "Small" },
};
var numberGroups = buckets.GroupBy(ap => ap.Size);
foreach (var grp in numberGroups)
{
var number = grp.Key;
var total = grp.Count();
}
foreach (var ap in grp)
Console.WriteLine(ap.Type " " grp.Key);
}
public class Ap
{
public string Type { get; set; }
public string Size { get; set; }
}
}
}
CodePudding user response:
Last foreach loop is erroneous and even it is not require,
Below will print your expected result,
foreach (var grp in numberGroups)
{
var size = grp.Key; //I renamed number variable to size
var total = grp.Count();
Console.WriteLine($"{grp.First().Type} {size} {total}");
}
Why the last loop is erroneous?
- In your last foreach loop, you are trying to iterate over
grpvariable which is not in the scope of class. You definedgrpas an iterator for your firstforeachloop. So the scope ofgrpvariable is limited to that loop only.
Why the last loop is not required?
- In your first foreach loop, you have all values which you would like to print on the console, you just need to write
Console.WriteLine()inside the same loop, rather than writing separateforeachloop for just printing the details.
CodePudding user response:
Your problem is here:
// This stores the data in groups, with the Size as key...
var numberGroups = buckets.GroupBy(ap => ap.Size);
// here, you're storing key and count in temporary variables,
// but not doing anything with them.
foreach (var grp in numberGroups)
{
var number = grp.Key;
var total = grp.Count();
}
Replace the last bit with this:
foreach (var grp in numberGroups)
{
Console.WriteLine("Apple " grp.Key " " grp.Count());
}
CodePudding user response:
Side note, perhaps one day your list will contain more than just apples, so you'd group by the type too and print it out:
var numberGroups = buckets.GroupBy(ap => new { ap.Size, ap.Type } );
foreach (var grp in numberGroups)
{
var typeAndSize = grp.Key;
var total = grp.Count();
Console.WriteLine($"Type: {typeAndSize.Type}, Size: {typeAndSize.Size}, Count: {total}");
}
The new { ap.Size, ap.Type } is a really useful device in c#; it's called an anonymous type, and it's like a mini class that the compiler writes for us so we don't have to write a dedicated one. It does some extra things that typical classes don't do, that make it really useful in a grouping situation; when GroupBy is assessing whether one class instance is equal to another it will use the Equals method. By default this comes from Object, the parent class of everything in C#. Object's Equals method returns true if the two things being compared live at the same memeory address in C#. That's useful, but if you have two different objects with the same data value but at different memory addresses (like you do with your two Large Apple) it would say they are not equal. This would mean if you just asked GroupBy to group your objects straight as they are, it wouldn't group anything because that are all considered not equal to each other. Anonymous types are considered equal if all their data is the same, so because two different instances are both "Large"and "Apple", GroupBy will count them as the same
(You could also provide your own version of Equals and GetHashCode that check two different Ap and compare their data, to achieve the same result, but for this use case it's easier to use an anonymous type)
