Сортировка строк

Есть куча файлов с именами

1.ts
2.ts
3.ts
...
9.ts
10.ts
11.ts
...
99.ts
100.ts
101.ts
102.ts
...
и т.д.

Если в проводнике винды выделить их все и начать куда-то перетаскивать, то туда они попадают не по порядку. Например, если взяться за 7-ой, то первыми прилетят 7, 8, 9, 10, 11..., а первые 6 будут где-нибудь в конце или середине списка. И так с любыми файлами, не зависимо от того, как они называются.
Проверял этим кодом:

        private void listView1_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Copy;
        }

        private void listView1_DragDrop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] strings = (string[])e.Data.GetData(DataFormats.FileDrop);
                foreach (string fp in strings)
                {
                    string fn = Path.GetFileName(fp);
                    ListViewItem item = new ListViewItem(fn);
                    long fileSize = GetFileSize(fp);
                    item.SubItems.Add(fileSize);
                    item.Tag = new FileChunk(fn, fileSize);
                    listView1.Items.Add(item);
                }
            }
        }

Вот и встал вопрос, как их отсортировать?
На Delphi можно так:

  if s1 < s2 then

Где-то раньше читал, что так можно только на Delphi и больше нигде. Не знаю, насколько это правда.
А на C# как?
Если есть список из вот таких объектов:

    internal class FileChunk
    {
        public string FileName { get; private set; }
        public long FileSize { get; private set; }

        public FileChunk(string fileName, long fileSize)
        {
            FileName = fileName;
            FileSize = fileSize;
        }
    }

как его отсортировать по FileName?

Врут, например, в С++ можно.

В C# вроде не определен такой оператор для строк, есть например String.Compare Method (System) | Microsoft Learn

Не канает.

        private static void SortChunks(List<FileChunk> chunks)
        {
            for (int i = 0; i < chunks.Count; ++i)
            {
                for (int j = 0; j < chunks.Count; ++j)
                {
                    if (i != j)
                    {
                        FileChunk chunkI = chunks[i];
                        FileChunk chunkJ = chunks[j];
                        int n = string.Compare(chunkI.FileName, chunkJ.FileName);
                        if (n < 0)
                        {
                            chunks[i] = chunkJ;
                            chunks[j] = chunkI;
                        }
                    }
                }
            }
        }

Получается так:
Screenshot
:man_shrugging:

Зачем свою медленную сортировку писать, даже в Дельфи давно есть готовые.

https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.sort?view=net-7.0#system-collections-generic-list-1-sort(system-comparison((-0)))

А это разве не то же самое получится? :thinking: Не похоже, чтобы оно быстрее было.
Зачем такое городить? Там, вроде, всё сводится к вызову CompareTo(...). Нельзя его просто в моём коде вызвать?

Потому что скорость не важна. Программа для одноразового использования.

Что городить? Наоборот просто передать функцию сравнения в Sort вместо кучи кода.

    // Default comparer for Part type.
    public int CompareTo(Part comparePart)
    {
          // A null value means that this object is greater.
        if (comparePart == null)
            return 1;

        else
            return this.PartId.CompareTo(comparePart.PartId);
    }
        // This shows calling the Sort(Comparison(T) overload using
        // an anonymous method for the Comparison delegate.
        // This method treats null as the lesser of two values.
        parts.Sort(delegate(Part x, Part y)
        {
            if (x.PartName == null && y.PartName == null) return 0;
            else if (x.PartName == null) return -1;
            else if (y.PartName == null) return 1;
            else return x.PartName.CompareTo(y.PartName);
        });

А что это за магия такая? Если в метод Sort передаётся делегат сравнения, зачем тогда в классе Part весь остальной код? Это перегрузка операторов сравнения?

Просто разные варианты.

То есть, весь смысл в этом: x.PartName.CompareTo(y.PartName);?

Ну там любая функция сравнивающая объекты.

Да, CompareTo это примерно то же самое, что и String.Compare Comparing Strings in .NET | Microsoft Learn

но разницы нет

        private static void SortChunks(List<FileChunk> chunks)
        {
            for (int i = 0; i < chunks.Count; ++i)
            {
                for (int j = 0; j < chunks.Count; ++j)
                {
                    if (i != j)
                    {
                        FileChunk chunkI = chunks[i];
                        FileChunk chunkJ = chunks[j];
                        int n = chunkI.FileName.CompareTo(chunkJ.FileName);
                        if (n < 0)
                        {
                            chunks[i] = chunkJ;
                            chunks[j] = chunkI;
                        }
                    }
                }
            }
        }

получается как на скриншоте.
И вот так тоже:

                chunks.Sort(delegate(FileChunk x, FileChunk y)
                {
                    if (x.FileName == null && y.FileName == null) return 0;
                    else if (x.FileName == null) return -1;
                    else if (y.FileName == null) return 1;
                    else return x.FileName.CompareTo(y.FileName);
                });

никакой разницы.

Добавьте поле типа Long к FileChunk, куда сохраните Convert.ToLong(Path.GetFileNameWithoutExtension(fp)), а потом по нему сортируйте.

Может просто выводится не тот список?

using System;
using System.Linq;

public class Program
{
	public static void Main()
	{
		Random rand = new Random();
		var items = Enumerable.Range(0, 10)
			.Select(i => new Tuple<string, int>(rand.Next(100).ToString(), i))
			.ToList();
		
		items.ForEach(Console.WriteLine);
		
		items.Sort((a, b) => a.Item1.CompareTo(b.Item1));
		
		Console.WriteLine("Sorted");
		items.ForEach(Console.WriteLine);
	}
}

https://dotnetfiddle.net/LXGjQf

UPD: а, так там всё правильно если сортировать как символы.

“2” > “19” это как “b” > “ab”

Он сортирует так

6
69
7
78
8
80
88
9
96
98

Может какая-нибудь секретная настройка есть для таких случаев?

То есть преобразовывать к числам, а потом сортировать? Я уже думал об этом.
Но тогда зачем дополнительное поле? Можно же сразу при сравнении это делать.

Чтобы сделать имена с числами сортируемыми, их обычно делают одинаковой длины и с нулями.
image0042

Этож придётся дофигища файлов вручную переименовывать. Кроме того, я хочу сохранить оригинальные имена.

Ну надо их так изначально называть )

А это не я их так называл :slightly_smiling_face:
Я, конечно, мог это поправить при скачивании. Но я люблю, чтобы всё было аутентично :point_up: (модное слово)