0

I have an object called simulation results.

 public SimulationResult
 {
        public Horse Winner {get;set;}
        public Horse Second {get;set;}
        public Horse Third {get;set;}
        public Horse Fourth {get;set;}
  }

  public Horse
  {
        public Guid Id{get;set;}
  }

So, I have a list of 50000 SimulationResult. How can I determine the top 50 most common results.

I tried using LINQ groupBy but the horseId appears in each object and it doesn't allow multiple occurrences of one value.

EDIT Sorry, thought it was clear. So we have 8 horses total. Say horse id is 1-8.

So in simulation result 1 the winner is 1, second is 2, third is 3, fourth is 4.

In simulation result 2 first is 5, second is 6 , third is 7, fourth is 8.

In simulation result 3 first is 1, second is 2, third is 3, fourth is 4.

So result set 1 and result set 3 are equal. So in this sample, winner 1 second 2 third 3 fourth 4 is the most common result.

DidIReallyWriteThat
  • 1,033
  • 1
  • 10
  • 39

3 Answers3

3

I tried using LINQ groupBy but the horseId appears in each object and it doesn't allow multiple occurrences of one value.

If you mean using anonymous type as explained in Grouping by Composite Keys, although most of the time we can let the compiler infer the names of us, we can always (and here it's necessary to) specify them explicitly:

var topResults = simulationResults
    .GroupBy(r => new
    { 
        WinnerId = r.Winner.Id,
        SecondId = r.Second.Id,
        ThirdId = r.Third.Id,
        FourthId = r.Fourth.Id,
    })
    .OrderByDescending(g => g.Count())
    .Select(g => g.First()) // or new { Result = g.First(), Count = g.Count() } if you need the count
    .Take(50)
    .ToList();
Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
  • this is beautiful and works perfect. Do you have a source for how you came up with this, or just lots of LINQ practice? – DidIReallyWriteThat Sep 24 '16 at 18:56
  • 1
    One source is of course the link in the answer, another is [Anonymous Types (C# Programming Guide](https://msdn.microsoft.com/en-us/library/bb397696.aspx), and then of course is the experience coming with a lot of experiments and SO puzzles :) – Ivan Stoev Sep 24 '16 at 19:32
1

Simplest answer to your question:

class ExactResult {
    public String CombinedId { get; set; }
    public int Count { get; set; }
}
resultList.Select(l => {
    var combinedId = l.Winner.Id.ToString() + l.Second.Id.ToString() + l.Third.ToString() + l.Fourth.ToString();
    return new ExactResult() { CombinedId = combinedId), Count = l.Count(c => c.Winner.Id.ToString() + c.Second.Id.ToString() + c.Third.ToString() + c.Fourth.ToString();)}
}).OrderByDescending(e => e.Count).Take(50)

The answer is meaningless though. If what you're really going for is the most likely 4 winners from a bunch of results, this is not the way to go about it. This will just display the most results with the EXACT same 4 winners. What you're probably looking for is statistical analysis or maybe spread. Anyway things more complicated than what you're actually asking.

TigOldBitties
  • 1,331
  • 9
  • 15
  • I'm looking for what I described(poorly). I figured out a way to get the most common 4 winners, but i need the most likely top 4 in the exact order also. – DidIReallyWriteThat Sep 24 '16 at 18:31
1

Maybe this is what you're looking for:

var q = (from x in mySimulationResultList
        group x by x into g
        let count = g.Count()
        orderby count descending
        select new { Value = g.Key, Count = count }).Take(50);

foreach (var x in q)
{
    Console.WriteLine($"Value: {x.Value.ToString()} Count: {x.Count}");
}

If you want meaningful output for the Console.WriteLine you would need to override ToString for Horse and SimulationResult

You must override Equals and GetHashCode for SimulationResult, something like this:

public override bool Equals(object obj)
{
    SimulationResult simResult = obj as SimulationResult;
    if (simResult != null)
    {
        if (Winner == simResult.Winner
            && Second == simResult.Second
            && Third == simResult.Third
            && Fourth == simResult.Fourth)
        {
            return true;
        }
    }
    return false;
}
public override int GetHashCode()
{
    int hash = 12;
    hash = hash * 5 + Winner.GetHashCode();
    hash = hash * 5 + Second.GetHashCode();
    hash = hash * 5 + Third.GetHashCode();
    hash = hash * 5 + Fourth.GetHashCode();
    return hash;
}

Sources here (group by query) and here (comparing objects against eachother)

Community
  • 1
  • 1
dukedukes
  • 266
  • 5
  • 10