Reputation: 7092
Lets say I have a list of asteroid objects like so:
Each asteroid has a title, a StartRoationPeriod, and a EndRoationPeriod.
I need to concatenate their names based on how close the current asteroid StartRoationPeriod and previous asteroid EndRoationPeriod are to an orbital constant and then spit out the concatenated title.
So with the above list, the final objects may look like this:
This requires me to keep track of both the current and previous asteroids.
I started to write the loop, but I'm unsure of where or even how to check the current asteroids start rotation period against the previous asteroids end rotation period...basically, it just gets messy fast...
string asteroid_title = string.Empty;
Asteroid prev_asteroid = null;
foreach (var asteroid in SolarSystem)
{
if (prev_asteroid != null)
{
if (asteroid.StartRoationPeriod + OrbitalConstant >= prev_asteroid.EndRoationPeriod)
{
asteroid_title = asteroid_title + asteroid.Title;
} else {
asteroid_title = asteroid.Title;
yield return CreateTitle();
}
}
prev_evt = evt;
}
Upvotes: 0
Views: 110
Reputation: 7618
I think this should work for you (If aggregate looks too complex try to convert it to a foreach,it's easy)
using System;
using System.Collections.Generic;
using System.Linq;
namespace Program
{
class Asteroid
{
public int EndRoationPeriod { get; internal set; }
public string Name { get; internal set; }
public int StartRoationPeriod { get; internal set; }
}
class AsteroidGroup
{
public int EndRoationPeriod { get; internal set; }
public string Names { get; internal set; }
}
internal class Program
{
private static void Main(string[] args)
{
int OrbitalConstant = 10;
List<Asteroid> SolarSystem = new List<Asteroid>()
{
new Asteroid() { Name= "9_Amphitrite" ,StartRoationPeriod=10 ,EndRoationPeriod=50},
new Asteroid() { Name= "24_Themis" ,StartRoationPeriod=45,EndRoationPeriod=100},
new Asteroid() { Name= "259_Aletheia",StartRoationPeriod=40 ,EndRoationPeriod=150},
new Asteroid() { Name= "31_Euphrosyne" ,StartRoationPeriod=60,EndRoationPeriod=200},
new Asteroid() { Name= "511_Davida" ,StartRoationPeriod=195,EndRoationPeriod=250},
new Asteroid() { Name= "87_Sylvia" ,StartRoationPeriod=90,EndRoationPeriod=300},
new Asteroid() { Name= "9_Metis" ,StartRoationPeriod=100,EndRoationPeriod=350},
new Asteroid() { Name= "41_Daphne" ,StartRoationPeriod=110,EndRoationPeriod=400},
};
var result = //I skip the first element because I initialize a new list with that element in the next step
SolarSystem.Skip(1)
//The first argument of Aggregate is a new List with your first element
.Aggregate(new List<AsteroidGroup>() { new AsteroidGroup { Names = SolarSystem[0].Name, EndRoationPeriod = SolarSystem[0].EndRoationPeriod } },
//foreach item in your list this method is called,l=your list and a=the current element
//the method must return a list
(l, a) =>
{
//Now this is your algorithm
//Should be easy to undrestand
var last = l.LastOrDefault();
if (a.StartRoationPeriod + OrbitalConstant >= last.EndRoationPeriod)
{
last.Names += " " + a.Name;
last.EndRoationPeriod = a.EndRoationPeriod;
}
else
l.Add(new AsteroidGroup { Names = a.Name, EndRoationPeriod = a.EndRoationPeriod });
//Return the updated list so it can be used in the next iteration
return l;
});
A more compact solution
var result = SolarSystem
.Skip(1)
.Aggregate( SolarSystem.Take(1).ToList(),
(l, a) => (a.StartRoationPeriod + OrbitalConstant >= l[l.Count - 1].EndRoationPeriod) ?
(l.Take(l.Count - 1)).Concat(new List<Asteroid> { new Asteroid() { Name = l[l.Count - 1].Name += " " + a.Name, EndRoationPeriod = a.EndRoationPeriod } }).ToList() :
l.Concat(new List<Asteroid> { a }).ToList()
);
Upvotes: 1