C# Sorting a List with numbers with colons or comma format

I had a problem where I had to sort a list where there where values with colons, like chapters or similar in ascending order. If you have a List with dot or comma values instead, you can use the same method.

  • 1:3
  • 1:4
  • 1:40
  • 1:5
  • 2:4
  • 5:9
  • 4:90
  • 3:500
  • 3:4
  • 1
  • 1:50

The sort order of this would be from the lowest number from the left side and the right side, like this:

  • 1
  • 1:3
  • 1:4
  • 1:5
  • 1:40
  • 1:50
  • 3:4
  • 3:500
  • 4:90
  • 5:9

Now it doesn’t seem that difficult, but it took me a while to figure out that there is a built-in class called Version for you to use which is perfect for this. I tried first simply convert and parse them as floats and sort them that way, but this works only until you reach the problem where you have 1:40 and 1:4 and they both would be parsed as 1,4 as the zeroes will be taken away. Same goes for 1:5 and 1:50, they would both be parsed as 1,5 and here as well would be a sorting problem since they are both seen as the same.

So that’s where the Version type comes in, we can parse a string in a version format. So instead of inventing the wheel again, let’s see what we can do with it.

If we want to use the Sort method, we could do it like this. First of all, create a new class, let’s call it MyAwesomeComparer.

	public class MyAwesomeComparer : Comparer<MyObjectWithTheColon>
	{
		public override int Compare(MyObjectWithTheColon x, MyObjectWithTheColon y)
		{
			Version outVerX = new Version();
			Version.TryParse(x.Name + ".0", out outVerX);

			Version outVerY = new Version();
			Version.TryParse(y.Name + ".0", out outVerY);

			return outVerX.CompareTo(outVerY);
		}
	}

MyObjectWithTheColon is my class I use my items for a List and in it this class, we have a name property, this is the property that contains the values such as above, for example 1:5. So for this to work we need to replace the colon so it becomes dots like this (see code below). Note that if you have a list of values with dots like 1.3, 1.4, then you don’t need to do this obviously. If you have a list of commas, then simply do the same Replace, but instead of replacing comma, replace your comma to a dot.

	public class MyAwesomeComparer : Comparer<MyObjectWithTheColon>
	{
		public override int Compare(MyObjectWithTheColon x, MyObjectWithTheColon y)
		{
			Version outVerX = new Version();
			Version.TryParse(x.Name.Replace(":", ".") + ".0", out outVerX);

			Version outVerY = new Version();
			Version.TryParse(y.Name.Replace(":", ".") + ".0", out outVerY);

			return outVerX.CompareTo(outVerY);
		}
	}

We replace the dot and try parse it with the Version.TryParse(), and then we retrive the value to our variable outVerX. We do the same thing for the other parameter y we are comparing and save the value to outVerY, and in the end we return the one who is bigger (see explanation on the int that returns here) with the CompareTo from the Version class. We can now use this overridden Comparer like this to get the sorted list!

MyList.Sort(new MyAwesomeComparer());

Flutter toJson and fromJson when you have an array

I couldn’t quite figure it out how to get it working when you have an object which has an array of objects in json format. This is what I ended up with. totalItems is a property in the FullWordList class, and this class contains a List of Items, which we declared further down. Both got toJson and fromJson methods which means they can get parsed by json.

And to have the whole object parsed we will first take in the data for FullWordList and inside the fromJson method, we will declare the first property totalItems simply from its value, but the items property will use the general from method from List to create an list with our values, and then we will use the map method to go through each object and use the Item’s fromJson method, and lastly we’ll call toList() to retrieve the List in a List<Item> format.

class FullWordList {
  int totalItems = -1;
  List<Item> items = [];
  FullWordList();

  FullWordList.fromJson(Map<String, dynamic> json)
      : totalItems = json['totalItems'],
        items = List.from(json['items']).map((e) => Item.fromJson(e)).toList();

  Map<String, dynamic> toJson() =>
      {'totalItems': this.totalItems, 'items': this.items};
}

class Item {
  String english = "";

  Item.fromJson(Map<String, dynamic> json) : english = json['english'];

  Map<String, dynamic> toJson() => {'english': this.english};
}

And this is how we could utilize the fromJson method for a FullWordList object using http to retrieve the data.

  Future<FullWordList> getDetails() async {
    var url = Uri.https('mywebsite.com',
        '/api/myapifunction', {"id": "65", "website": "fileidea"});

    // Await the http get response, then decode the json-formatted response.
    var response = await http.get(url);
    print(convert.jsonDecode(response.body));
    print(response.statusCode);

    if (response.statusCode == 200) {
      var jsonResponse = convert.jsonDecode(response.body);
      FullWordList dataList = FullWordList.fromJson(jsonResponse);
      return dataList;
    } else {
      print('Request failed with status: ${response.statusCode}.');
      return new FullWordList();
    }
  }