# Linq: round-robin ordering based on segments

**Date:** 2017-10-28  
**Author:** Kees C. Bakker  
**Categories:** .NET / C#  
**Original:** https://keestalkstech.com/linq-round-robin-ordering-based-segments/

![Linq: round-robin ordering based on segments](https://keestalkstech.com/wp-content/uploads/2017/10/2017-10-28_1401.jpg)

---

[Linq](https://msdn.microsoft.com/en-us/library/bb308959.aspx?f=255&MSPPError=-2147217396) is a wonderful way to work with lists in C#. This article focuses on how you can create a round-robin ordering for segments of your list. It will distribute items of each segment evenly over the list.

> A round robin is an arrangement of choosing all elements in a group equally in some rational order (...) A simple way to think of round robin is that it is about "taking turns." Used as an adjective, round robin becomes "round-robin. [Source: definition by What Is](http://whatis.techtarget.com/definition/round-robin)
>
> — *Source: definition by What Is*

## The problem

Let's say we have a list of download URLs and we need to create a program that downloads a file from each URL. The list might look a little bit like this:

```cs
var urls = new string[] {
  "https://a.com?download=1.mp3",     "https://a.com?download=2.mp3", 
  "https://a.com?download=3.mp3",     "https://a.com?download=4.mp3", 
  "https://b.nl?download=alpha.mp3",  "https://b.nl?download=beta.mp3", 
  "https://b.nl?download=gamma.mp3",  "https://b.nl?download=delta.mp3", 
  "https://c.es?download=i.mp3",      "https://c.es?download=ii.mp3", 
  "https://c.es?download=iii.mp3",    "https://c.es?download=iv.mp3"
};
```

Question: How can we process this list in such a way that we put the least pressure on the hosts?
Answer: Order the list in such a way that the program will download: file **1** from **a.com** first, next file **1** from **b.nl**, next file **1** from **c.es** before continuing with file **2** form **a.com** until all the files are downloaded.

## But how?

The basic idea is as follows:

## Show me some code!

Let's put the idea into code:

```cs
var x = urls
			
	//convert the urls to uri's
	.Select(u => new Uri(u))
			
	//create groups of unique hosts
	.GroupBy(u => u.Host)
			
	//select them back together into a single list
	.SelectMany((group, groupIndex) => group.Select((item, index) => new { Index = index, GroupIndex = groupIndex, Value = item }))
			
	//order by the group item index
	.OrderBy(u => u.Index)
			
	//order by the group index
	.ThenBy(u => u.GroupIndex)
			
	//show position (or one could select u.Value.ToString() for just the URL)
	.Select((u, position) => new { Position = position, Index = u.Index, GroupIndex = u.GroupIndex, Value = u.Value });
		
//write it to the console		
x.ToList().ForEach(u => Console.WriteLine(u));
```

The `Select` and `SelectMany` methods provide indexes that we leveraged to do the actual ordering. The console will show the following feedback:

```cs
{ Position = 0, Index = 0, GroupIndex = 0, Value = https://a.com/?download=1.mp3 }
{ Position = 1, Index = 0, GroupIndex = 1, Value = https://b.nl/?download=alpha.mp3 }
{ Position = 2, Index = 0, GroupIndex = 2, Value = https://c.es/?download=i.mp3 }
{ Position = 3, Index = 1, GroupIndex = 0, Value = https://a.com/?download=2.mp3 }
{ Position = 4, Index = 1, GroupIndex = 1, Value = https://b.nl/?download=beta.mp3 }
{ Position = 5, Index = 1, GroupIndex = 2, Value = https://c.es/?download=ii.mp3 }
{ Position = 6, Index = 2, GroupIndex = 0, Value = https://a.com/?download=3.mp3 }
{ Position = 7, Index = 2, GroupIndex = 1, Value = https://b.nl/?download=gamma.mp3 }
{ Position = 8, Index = 2, GroupIndex = 2, Value = https://c.es/?download=iii.mp3 }
{ Position = 9, Index = 3, GroupIndex = 0, Value = https://a.com/?download=4.mp3 }
{ Position = 10, Index = 3, GroupIndex = 1, Value = https://b.nl/?download=delta.mp3 }
{ Position = 11, Index = 3, GroupIndex = 2, Value = https://c.es/?download=iv.mp3 }
```

Source: [When the code runs .Net Fiddle](https://dotnetfiddle.net/owIkjq)

## Conclusion

A round-robin ordering based on segments is easy to make in C# Linq. Use `GroupBy` to create the segments, use `SelectMany` to create a simple list with indexes and use `OrderBy` and `ThenOrderBy` to sort the list on the `index` and `groupIndex`.
