0

I'm working on aforge. I have a list of data which I Draw on the screen next to blobs. I'm also adding the data to a list box. But Instead of getting added in a left to right sequence, its getting added as per the blob's XY coordinate as shown below in the first listbox.

enter image description here

I tried to sort the list using Linq by the OrderBy method but then it orders the whole list in ascending order. I dont want that, I want the list to be sorted by the first line, then the next line and so on. I tried using take<> to sort it by the first row, but it only sorts the first row of 5 int and then stops.

Code :

        int n = 5;
        elements = elements.Take(n).OrderBy(i => i).ToList();
        foreach (var cogxx in elements)
        {
           listBox2.Items.Add(cogxx);                
        }

If List coord = new List{80,90,100,60,70,20,40,30,10,50,} if user input int row is 2 then output should be {60,70,80,90,100,10,20,30,40,50} How can I do this?

Roshan
  • 149
  • 1
  • 9
  • The line number and the int should be two properties of a class. Then `OrderBy(z => z.LineNumber).ThenBy(z => z.IntProperty)`. – mjwills Feb 23 '19 at 12:54

1 Answers1

0

If you have no special class representing your Line object, then you can use regex to parse the string. In this case, I use name capture group of Regex:

List<string> elements = new List<string>
{
    "Line 1 int 1",
    "Line 2 int 1",
    "Line 1 int 2",
    "Line 1 int 3",
    "Line 2 int 2",
    "Line 2 int 12",
};

var pattern = @"^\bLine \b(?<num1>\d+) \bint \b(?<num2>\d+)$";
Regex regex = new Regex(pattern);

var query =
    from e in elements
    where regex.Match(e).Success
    orderby 
        int.Parse(regex.Match(e).Groups["num1"].Value), 
        int.Parse(regex.Match(e).Groups["num2"].Value)
    select e;

var orderedResult = query.ToList();

Or the same with fluent API LINQ:

var orderedResult =
        elements
            .Where(e => regex.Match(e).Success)
            .OrderBy(e => int.Parse(regex.Match(e).Groups["num1"].Value))
            .ThenBy(e => int.Parse(regex.Match(e).Groups["num2"].Value))
            .ToList();

The orderedResult should be:

Line 1 int 1 
Line 1 int 2 
Line 1 int 3 
Line 2 int 1 
Line 2 int 2 
Line 2 int 12 

UPDATE:

Create a class and extension methods that would split your list into chunks:

public static class MyLinqExtensions
{
    public static IEnumerable<IEnumerable<T>> Batch<T>(
        this IEnumerable<T> source, int batchSize)
    {
        using (var enumerator = source.GetEnumerator())
            while (enumerator.MoveNext())
                yield return YieldBatchElements(enumerator, batchSize - 1);
    }

    private static IEnumerable<T> YieldBatchElements<T>(
        IEnumerator<T> source, int batchSize)
    {
        yield return source.Current;
        for (int i = 0; i < batchSize && source.MoveNext(); i++)
            yield return source.Current;
    }
}

This code was taken from this answer.

Then you use Batch extension method the following way:

List<int> coord = new List<int> { 80, 90, 100, 60, 70, 20, 40, 30, 10, 50 };

int n = 5;
var orderedResult = 
    coord.Batch(n)
        .Select(b => b.OrderBy(i => i))
        .SelectMany(x => x)
        .ToList();

If you want to learn LINQ, LINQPad is your friend.

Dmitry Stepanov
  • 2,776
  • 8
  • 29
  • 45
  • Hi, I get an error that regex.Match(string) has some invalid arguments. also, what is e? – Roshan Feb 23 '19 at 13:30
  • I get the same error in Linq as well - regex.Match(string) has some invalid arguments – Roshan Feb 23 '19 at 13:34
  • @Roshan, `e` is an element of your `elements` list. I don't have `regex.Match(string)`. I have `regex.Match(e)` – Dmitry Stepanov Feb 23 '19 at 13:35
  • im executing this in a button, so e is the eventargs. If I substitute it with another letter, it gives me that error, says cannot convert from int to string. – Roshan Feb 23 '19 at 13:37
  • data in elements are int – Roshan Feb 23 '19 at 13:39
  • @Roshan, I assumed that you have a list of strings named `elements`: "Line 1 int 1" and so on. You can change `e` in my code to whatever you want, say, `el` to differe from your `e` event. – Dmitry Stepanov Feb 23 '19 at 13:43
  • Hi Dmitry, I changed that. I created a new string list and copied values of int after converting. It does not give any output, count of orderedResult is always 0 – Roshan Feb 23 '19 at 13:45
  • Hi Dmitry, Line 1 int 1 is the format of the output I wanted. The list will always be int (123) or string(123) There will not be any text as int or line in the output. I think the regex is based on that. – Roshan Feb 23 '19 at 13:53
  • @Roshan, yes, regex is based on that. I thought you had a list of strings:"Line 1 int 1" and so on. What is the structure and content of your `elements` variable? – Dmitry Stepanov Feb 23 '19 at 14:04
  • It is X coordinate from blobs, so if there are 10 blobs there would be 10 X coordinates without the decimal in the list, listdata[0] would have first coordinate and listdata[9] would have the 10th coordinate. These coordinates would be divided by a user specified int as rows, so if row is 2 then first row would have 5 coordinates and second row would have 5 coordinates. So, we have to sort the coordinates in ascending order of first row and then the second row. And then store it in a list in that order – Roshan Feb 23 '19 at 14:20
  • Example : List coord = new List{80,90,100,60,70,20,40,30,10,50,} if user select int row is 2 then output should be {60,70,80,90,100,10,20,30,40,50} – Roshan Feb 23 '19 at 14:22
  • PERFECT!!!! Thank you Dmitry for all the help and appreciate the time you put into this. – Roshan Feb 23 '19 at 14:51