C # Сортировка массива FileInfo по имени, получение неожиданных результатов и необходимость знать, есть ли у меня другие варианты сортировки - PullRequest
1 голос
/ 16 февраля 2012

Я сохраняю файлы изображений в следующем формате: 1-6784 (1 - порядок сортировки, который я хочу видеть, и 6784 случайное число от 1000 до 9999.

Когда я смотрю на папку через проводник и упорядочить по имени они все выглядят хорошо и отсортированы по на первый номер, т. е. (1-XXXX, 2-XXXX, 9-XXXX, 12-XXXX и т. д.) в порядке возрастания.

Однако, когда я получаю массив FileInfo для этого каталога, он автоматически сортирует его по названию, я полагаю, но по какой-то причине он разместил бы 10-XXXX и 11-XXXX раньше 1-XXXX, 2-XXXX и т. Д. Так что до 10 все в порядке, и порядок сохраняется, когда ссылки src изображения создаются в виде в моем веб-приложении, но после загрузки \ сохранения более 9 файлов двойные цифры 10, 11 и т. д. занимают первые позиции в массиве над однозначными числами.

DirectoryInfo sourceDir = new DirectoryInfo(System.Web.HttpContext.Current.Request.MapPath("~/Content/ProductImages/" + Model.Products[i].ProductID.ToString() + "/thumbs/"));

                   if (sourceDir.Exists)
                   {

                       FileInfo[] fileEntries = sourceDir.GetFiles();
                       Array.Sort(fileEntries, (f1, f2) => f1.Name.CompareTo(f2.Name));


}

Ответы [ 6 ]

3 голосов
/ 16 февраля 2012

Вам нужно дополнить свой порядок сортировки ведущими нулями:

0001-XXX
0002-XXX
...

Или вы можете попробовать следующее для сортировки выходных файлов:

FileInfo[] fileEntries = sourceDir.GetFiles()
   .OrderBy(f => Regex.Match(f.Name, "^[0-9]+").Value.PadLeft(10, '0'))
   .ToArray();
3 голосов
/ 16 февраля 2012

Описание

Вы сортируете строку, и это правильный результат.

Это лексикографическая сортировка, которая означает, что в основном язык обрабатывает переменные как строки и сравнивает символ за символом («200» больше, чем «19999», поскольку «2» больше, чем «1»)...

Источник Почему некоторые методы сортировки сортируются по 1, 10, 2, 3…?

Решение

Я предлагаю вам создать пользовательский Comparer, который дополняет начальные нули до имени файла.

public class MyCustomComparer : IComparer<FileInfo>
{
    public int Compare(FileInfo x, FileInfo y)
    {
        // split filename
        string[] parts1 = x.Name.Split('-');
        string[] parts2 = y.Name.Split('-');

        // calculate how much leading zeros we need
        int toPad1 = 10 - parts1[0].Length;
        int toPad2 = 10 - parts2[0].Length;

        // add the zeros, only for sorting
        parts1[0] = parts1[0].Insert(0, new String('0', toPad1));
        parts2[0] = parts2[0].Insert(0, new String('0', toPad2));

        // create the comparable string
        string toCompare1 = string.Join("", parts1);
        string toCompare2 = string.Join("", parts2);

        // compare
        return toCompare1.CompareTo(toCompare2);
    }
}

И вызывает их

FileInfo[] fileEntries = sourceDir.GetFiles();
Array.Sort(fileEntries, new MyCustomComparer());

Дополнительная информация

1 голос
/ 16 февраля 2012

Вы можете разобрать числа и сравнить их следующим образом:

DirectoryInfo sourceDir = new DirectoryInfo(System.Web.HttpContext.Current.Request.MapPath("~/Content/ProductImages/" + Model.Products[i].ProductID.ToString() + "/thumbs/"));

if (sourceDir.Exists)
{
    FileInfo[] fileEntries = sourceDir.GetFiles();
    Array.Sort(fileEntries,
        delegate(FileInfo x, FileInfo y)
        {
            String[] xvals = x.Name.Split('-');
            String[] yvals = y.Name.Split('-');

            int cmp = Int32.Parse(xvals[0]).CompareTo(Int32.Parse(yvals[0]));
            if (cmp != 0)
            {
                return cmp;
            }

            cmp = Int32.Parse(xvals[1]).CompareTo(Int32.Parse(yvals[1]));
            return cmp;
        }
    );
}
1 голос
/ 16 февраля 2012

Причина понятна: имя файла является строкой, а в качестве строки «11» следует после «1», но перед «2».

Чтобы сделать то, что вы хотите, в вашей функции сравнения вам нужно будет проанализировать имя и сравнить части (разделенные тире) как числа (просто приведите и сравните)

0 голосов
/ 16 февраля 2012

Если вы не хотите изменять имена файлов, вы можете выполнить заполнение во время сравнения.Я решил добавить к десяти числам, но, возможно, их должно быть больше, в зависимости от того, сколько у вас файлов.

Array.Sort(fileEntries, (f1, f2) => f1.Name.PadLeft(10, '0').CompareTo(f2.Name.PadLeft(10, '0'));
0 голосов
/ 16 февраля 2012

Как насчет предварительного заполнения ваших чисел нулями, чтобы они были фиксированной длины.Таким образом, буквенно-цифровое сравнение даст тот же результат, что и ожидаемое числовое сравнение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...