C #, сортировка объектов в списке по имени

как я могу отсортировать объекты в списке по их имени? Пример:

mapPart_1_0
mapPart_1_2
mapPart_1_4
mapPart_1_6
mapPart_1_8
mapPart_1_10
mapPart_1_12
mapPart_1_24
mapPart
mapPart_1_0
mapPart_1_1
mapPart_1_2
mapPart_1_3
mapPart_1_4
mapPart_1_5
...
mapPart_2_1
mapPart_2_2
mapPart_2_3
...
mapPart_2_11
...
1 mapPart
mapPart_1_0
mapPart_1_1
mapPart_1_2
mapPart_1_3
mapPart_1_4
mapPart_1_5
...
mapPart_2_1
mapPart_2_2
mapPart_2_3
...
mapPart_2_11
...
11 Big list continues... (somewhere in that list are missing that aper in sorted one)

В:

mapPart_1_0
mapPart_1_1
mapPart_1_2
mapPart_1_3
mapPart_1_4
mapPart_1_5
...
mapPart_2_1
mapPart_2_2
mapPart_2_3
...
mapPart_2_11
...

Или я могу изменить имя объекта на другое, чтобы его было легче сократить?

Спасибо.


person Semas    schedule 11.08.2010    source источник
comment
Второй список не похож на отсортированный первый. Например, второй список содержит элемент mapPart_1_5, которого нет в первом списке. Уточните, например, имея все элементы в обоих списках, один из которых не сортируется, а другой сортируется. Я не уверен, достаточно ли ясен этот вопрос для хорошего ответа.   -  person Manfred    schedule 11.08.2010
comment
не очевидно, что вы хотите изменить. ваш первый пример отсортирован по имени в естественном порядке (то есть от 2 до 10), и из вашего второго примера невозможно определить, является ли он таким (естественная или строгая сортировка дала бы точно такой же результат). кажется, вы только что удалили несколько предметов ...?   -  person David Hedlund    schedule 11.08.2010


Ответы (6)


Это включает в себя некоторые либеральные предположения о ваших требованиях и является быстрым взломом, но ...

var groups = myList.Select (text => 
new
 { 
  FirstNum = int.Parse(text.Split('_')[1]), 
  SecondNum = int.Parse(text.Split('_')[2])
 })
.GroupBy(a => a.FirstNum, a => a.SecondNum);


foreach(var group in groups.OrderBy(g => g.Key))
{
  int min = group.Min();
  int max = group.Max();

  for(int i=min; i<=max; i++)
    yield return string.Format ("mapPart_{0}_{1}", group.key, i);

}
person Ani    schedule 11.08.2010
comment
Спасибо! Это помогло мне выделить. - person Semas; 11.08.2010
comment
Без проблем. Конечно, есть люди, которые могли бы дать лучший ответ, если бы только вы могли более четко сформулировать постановку проблемы. - person Ani; 11.08.2010

Возможно, вы захотите использовать естественную сортировку.

Обычный сорт:

  • mapPart_1_1
  • mapPart_1_10
  • mapPart_1_2

Натуральный сорт:

  • mapPart_1_1
  • mapPart_1_2
  • mapPart_1_10

Вы можете прочитать Естественная сортировка в C #.

person Mark Byers    schedule 11.08.2010

Я думаю, вы могли бы сделать что-то подобное (не проверено)

var yourList= new List<YourObject>();
//add items to your list

yourList.Sort(delegate(YourObject p1, YourObject p2)
              {
                  //you can make this delegate more complex if you need it
                  return p1.Name.CompareTo(p2.Name);
              });
person Jonathan    schedule 11.08.2010

[Отметьте] [1] этот вопрос

вам нужна функция сортировки с настраиваемым IComparer. Теперь у вас есть icomparer по умолчанию, когда вы используете сортировку. это проверит значение поля.

Когда вы создаете настраиваемый IComparer (вы делаете это в своем классе, реализуя Icomparable интерфейс). что он делает: ваш объект проверяет себя на все остальные объекты в сортируемом вами списке.

это делается функцией. (не волнуйтесь, VS будет реализовывать это при обращении к вашему интерфейсу

public class  ThisObjectCLass : IComparable{

    public int CompareTo(object obj) {
            ThisObjectCLass something = obj as ThisObjectCLass ;
            if (something!= null) 
                if(this.key.Split("_")[1].CompareTo(object.key.Split("_")[1]) == 0){
                // extratc the numbers from your name and compare the numbers, you have            to add some logic but I assume you know something about c#
                //then:
                   if .....
                }
                else if(this.key.Split("_")[1] "is more important then(use some logic here)" object.key.Split("_")[1]){
                 return 1
                }
                else return -1
            else
               throw new ArgumentException("I am a dumb little rabid, trying to compare different base classes");
        }
}

читайте по ссылкам выше для получения дополнительной информации.

person Nealv    schedule 11.08.2010

Похоже, это может быть то, что вы хотели, если вы хотите, чтобы сортировка подчинялась каждому токену? Честно говоря, я не уверен, какими вы хотите добиться результатов ...

class Program
{
    public class ObjectNameComparer : IComparer<object>
    {
        public int Compare(object x, object y)
        {
            var n1 = x.ToString().Split('_');
            var n2 = y.ToString().Split('_');
            var nameCompare = string.Compare(n1[0], n2[0], StringComparison.OrdinalIgnoreCase);
            if (nameCompare == 0)
            {
                var i1 = int.Parse(n1[1]);
                var i2 = int.Parse(n2[1]);
                if (i1 == i2)
                {
                    var i12 = int.Parse(n1[2]);
                    var i22 = int.Parse(n2[2]);
                    return i12 - i22;
                }
                return i1 - i2;
            }
            return nameCompare;
        }
    }

    static void Main(string[] args)
    {
        var objectList = new List<object>();

        objectList.AddRange(new object[]
            {
                "mapPart_1_0",
                "mapPart_1_10",
                "mapPart_100_10",
                "mapPart_1_12",
                "mapPart_22_11",
                "mapPart_1_24",
                "mapPart_2_1",
                "mapPart_10_24",
                "mapPart_2_11",
            });

        var ordered = objectList.OrderBy(a => a, new ObjectNameComparer());

    }
}
person Codesleuth    schedule 11.08.2010

однострочное решение, которое я предпочитаю для строки!

//Sort by Name: list = List<string>() ...
list.Sort((x, y) => String.Compare(x, y, StringComparison.Ordinal));
person tom nobleman    schedule 13.12.2013