Сучасна диджитал-освіта для дітей — безоплатне заняття в GoITeens ×
Mazda CX 30
×

Задача на сортировку (С#)

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

Всем Привет,

Что-то последние неск часов залип с следующей задачей.

Есть код на шарпе, который должен отсортировать это список примерно в том виде в котором он уже есть. Визуально можно оценить принцип сортировки этих строк, каждая из которых представляет путь в дереве, а в квадратных скобках индекс в коллекции.

class Program
    {
        private static string str =
      @"Aaa
        Bbb
        Cccc
        Comments\[0]\Aaa
        Comments\[0]\Bbb
        Comments\[0]\Array\[0]
        Comments\[0]\Array\[1]
        Comments\[0]\Array\[4]
        Comments\[0]\Array\[4]
        Comments\[0]\Childs\[0]\Aaa
        Comments\[0]\Childs\[0]\Bbb
        Comments\[0]\Childs\[0]\Likes\[0]
        Comments\[0]\Childs\[0]\Likes\[4]
        Comments\[0]\Childs\[0]\Likes\[4]
        Comments\[0]\Childs\[1]\Aaa
        Comments\[0]\Childs\[1]\Bbb
        Comments\[0]\Childs\[1]\Likes\[0]
        Comments\[0]\Childs\[1]\Likes\[4]
        Comments\[0]\Childs\[1]\Likes\[4]
        Comments\[0]\Childs\[4]
        Comments\[0]\Childs\[4]
        Comments\[4]
        Comments\[4]";
        static int CompareTo(string x, string y)
        {
            var attr1 = x.Split('\\');
            var attr2 = y.Split('\\');
            //compare by path
            var countPath1 = attr1.Length;
            var countPath2 = attr2.Length;
            var minCountPath = Math.Min(countPath1, countPath2);
            for (ushort i = 0; i < minCountPath; i++)
            {
                var pathName1 = attr1[i];
                var pathName2 = attr2[i];
                if (pathName1 != pathName2)
                {                 
                        return pathName1.CompareTo(pathName2);
                }
            }
            return 0;
        }
        static void Main(string[] args)
        {
            var list = str.Split('\n', StringSplitOptions.RemoveEmptyEntries)
                          .Select(x => x.Trim())
                          .ToList();
            list.Sort((x, y) => CompareTo(x, y));
            var newStr = string.Join('\n', list);
            Console.WriteLine(newStr);
        }
    }

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

Aaa
Bbb
Cccc
Comments\[0]\Aaa
Comments\[0]\Array\[0]
Comments\[0]\Array\[1]
Comments\[0]\Array\[4]
Comments\[0]\Array\[4]
Comments\[0]\Bbb
Comments\[0]\Childs\[0]\Aaa
Comments\[0]\Childs\[0]\Bbb
Comments\[0]\Childs\[0]\Likes\[0]
Comments\[0]\Childs\[0]\Likes\[4]
Comments\[0]\Childs\[0]\Likes\[4]
Comments\[0]\Childs\[1]\Aaa
Comments\[0]\Childs\[1]\Bbb
Comments\[0]\Childs\[1]\Likes\[0]
Comments\[0]\Childs\[1]\Likes\[4]
Comments\[0]\Childs\[1]\Likes\[4]
Comments\[0]\Childs\[4]
Comments\[0]\Childs\[4]
Comments\[4]
Comments\[4]

Понятно, что самый очевидный способ отсортировать, это строить полноценное дерево с нодами и постепенно в него вставлять элементы, а потом обходить это дерево. Но не хочется набирать много кода. Неужели нельзя модифицировать int CompareTo(string x, string y) ф-цию чтобы она дала правильный вид сортировки ?

👍ПодобаєтьсяСподобалось0
До обраногоВ обраному0
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Я бы по быстрому сделал дерево и отсортировал листы и ветки дерева, а потом рекурсивно прошелся по дереву и сформировал список.

Кода чуть больше, но можно не думать, так как основано на готовых паттернах.

Кому интересно.
Вчера писал что решение найдено dou.ua/...​rums/topic/35446/#2276960,
оно такое для шарпа. Не хватало одного ифа в CompareTo ф-ции.

static int CompareTo(string x, string y)
        {
            var attr1 = x.Split('\\');
            var attr2 = y.Split('\\');

            var countPath1 = attr1.Length;
            var countPath2 = attr2.Length;

            var minCountPath = Math.Min(countPath1, countPath2);

            for (ushort i = 0; i < minCountPath; i++)
            {
                var pathName1 = attr1[i];
                var pathName2 = attr2[i];

                if (pathName1 != pathName2)
                {
                    //new IF
                    if (i < minCountPath - 1 || pathName1[0] == '[' || i == 0) 
                    {
                        return pathName1.CompareTo(pathName2);
                    }
                    else
                    {
                        return countPath1.CompareTo(countPath2);
                    }
                }
            }

            return 0;
        }

Это решение как продолжение мысли этого решения
dou.ua/...​sb_comments_forum#2276715

Тссс... дай дитю потюнить наносекунды и нинобайты на никому не нужной поделке-перделке :-)))

потюнить наносекунды и нинобайты на никому не нужной поделке-перделке

Меня пока что устраивает эта гипотеза в околонаучных кругах.
Главное чтобы мне никто не мешал =)

Очень дорогая «CompareTo», особенно «.Split».

for (ushort i = 0; i < minCountPath; i++)

Может даже негативно сказаться на производительности, где итерации через int будут чуть быстрее (проверялось на x64 с 16 битными asm командами и 32-битными).

if (i < minCountPath — 1 || pathName1[0] == ’[’ || i == 0)

Еще не индусский код, но уже близко.

В оригинальном коде нет этого сплит, это я для наглядности переделал для Доу, чтобы получить маленький самодостаточный пример. Также в оригинале я убрал i==0 oн мне не нужен, оставил его здесь поскольку было бы неправильно если бы мой пример работал не так как была постановка задачи на Доу, а она немного но отличается от оригинальной задачи.
Ну и последнее, я знаю как переписать эту сортировку на Си и она будет работать максимально быстро, но я не могу ее применить в шарпе

static CONTENT: &str = r#"Aaa
Bbb
Cccc
Comments\[0]\Aaa
Comments\[0]\Bbb
Comments\[0]\Array\[0]
Comments\[0]\Array\[1]
Comments\[0]\Array\[4]
Comments\[0]\Array\[4]
Comments\[0]\Childs\[0]\Aaa
Comments\[0]\Childs\[0]\Bbb
Comments\[0]\Childs\[0]\Likes\[0]
Comments\[0]\Childs\[0]\Likes\[4]
Comments\[0]\Childs\[0]\Likes\[4]
Comments\[0]\Childs\[1]\Aaa
Comments\[0]\Childs\[1]\Bbb
Comments\[0]\Childs\[1]\Likes\[0]
Comments\[0]\Childs\[1]\Likes\[4]
Comments\[0]\Childs\[1]\Likes\[4]
Comments\[0]\Childs\[4]
Comments\[0]\Childs\[4]
Comments\[4]
Comments\[4]"#;


#[derive(Ord, PartialOrd, Eq, PartialEq)]
enum SortKeyPart<'a> {
    FinalKey(&'a str),
    Key(&'a str),
    Index(usize),
}

fn main() {


    let mut lines: Vec<_> = CONTENT.split("\n").collect();
    lines.sort_by_cached_key(|l| get_sort_key(l));
    
    for l in &lines {
        println!("{}", l)
    }
    
    let sorted_content: String = lines.join("\n");
    
    assert_eq!(CONTENT, sorted_content);
}

fn get_sort_key(s: &str) -> Vec<SortKeyPart> {
    let mut sort_key = vec![];
    let parts : Vec<_> = s.split("\\").collect();
    
    let parts_count = parts.len();
    
    for (i, p) in parts.into_iter().enumerate() {
        let key_part = if let Some(idx) = try_parse_index(p) {
            SortKeyPart::Index(idx)
        } else {
            if i < parts_count - 1 {
                SortKeyPart::Key(p)
            } else {
                SortKeyPart::FinalKey(p)
            }
        };
        
        sort_key.push(key_part);
    }
    
    sort_key
}

fn try_parse_index(s: &str) -> Option<usize> {
    if s.chars().nth(0) == Some('[') && s.chars().nth_back(0) == Some(']') {
        s[1..(s.len() - 1)].parse().ok()
    } else {
        None
    }
}

Запустить в песочнице: play.rust-lang.org/...​900e588fac87e830430083823

Как-то много бойлерплейта что б за растом бегать с теми же фичами доступными в .NET

open System
open System.Text.RegularExpressions

let input =
            @"Aaa
            Bbb
            Cccc
            Comments\[0]\Aaa
            Comments\[0]\Array\[0]
            Comments\[0]\Array\[1]
            Comments\[0]\Array\[4]
            Comments\[0]\Array\[4]
            Comments\[0]\Childs\[0]\Aaa
            Comments\[0]\Bbb
            Comments\[0]\Childs\[0]\Bbb
            Comments\[0]\Childs\[0]\Likes\[0]
            Comments\[0]\Childs\[0]\Likes\[4]
            Comments\[0]\Childs\[0]\Likes\[4]
            Comments\[0]\Childs\[1]\Aaa
            Comments\[0]\Childs\[1]\Bbb
            Comments\[0]\Childs\[1]\Likes\[0]
            Comments\[0]\Childs\[1]\Likes\[4]
            Comments\[0]\Childs\[1]\Likes\[4]
            Comments\[0]\Childs\[4]
            Comments\[0]\Childs\[4]
            Comments\[4]
            Comments\[4]"
            
            
type PathElement =
            | End of string
            | StrEl of string
            | IdxEl of int

[<EntryPoint>]
let main argv =
     
            
      let inputArray = input.Split(Environment.NewLine)
        
      let getPathElement str lst =
            match Regex.Match(str, "[(\d+)]", RegexOptions.Compiled).Captures with
            |  :? CaptureCollection as cpt when cpt.Count = 1 -> (int >> IdxEl) <| cpt.[0].Value
            | _ when lst -> End str
            | _ -> StrEl str
         
      let convertToPathElList (str: String) =
                    let inputPath = str.Trim().Split("\\")
                    inputPath
                               |> Array.fold (fun (state, idx) path ->
                                                  state @ [getPathElement path (idx=inputPath.Length-1)],idx+1)
                                                  (List.empty<PathElement> , 0)
                                                  ,str
                    
      let output = inputArray
                  |> Array.map convertToPathElList 
                  |> Array.sortBy(fun (elements, _) -> elements)
                  |> Array.iter(fun (_, path) ->  printf "%s\n" path)
      0
bit.ly/3HBsxWJ

Нихрена, я встретил живого человека пишущего на F# О_о Доу срочно должны взять у Вас интервью:)
P.S. Не знаю как реагировать, но в полицию на всякий случай позвонил.

F# о*уенен. Окамл даже лучше, но экосистема...

F# о*уенен

Да, но это не совсем его кейс. Впринципе все три примера, на С# F# и Rust,
примерно одинаковы.
Все три с единственной целью, чтобы втянуть в середину сортировки полезный иф для inputPath.Length-1 и плюс до сотни строчек обвязки на подготовку данных, сортировку и вывод на экран.

фикс битой регулярки

отож

bit.ly/3Dx3bXG

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

Как-то много бойлерплейта что б за растом бегать с теми же фичами доступными в .NET

Сорян, но когда выбор между Си-подобным синтаксисом плюс немного бойлерплейта и вот такой вот непонятной хуитой, которая уже не вмещается в экран по ширине, для меня выбор очевиден.

А про fold и иммутабельность в расте пока еще не слышал наверное?
stackoverflow.com/...​-to-use-a-fold-with-a-vec

В целом F# тут тоже мало от раста отличается и позволяет писать for .. in .. if .. else и оперировать мутабельными коллекциями неосиляторам и тоже без бойлерлейта.

Пример же о том, что в .net сделать structural compare по коллекциям и du еще проще, если сильно надо, rust для этого не нужен.

А про fold

В F# не завезли map?

и иммутабельность в расте пока еще не слышал наверное?

Я думаю ты ошибся форумом, тебе сюда: www.reddit.com/...​erators_harm_readability

stackoverflow.com/...​-to-use-a-fold-with-a-vec

Это как минимум делается с использованием константной памяти.

(0..n).fold((0, 1), |(n0, n1), _| (n1, n0 + n1)).0
В F# не завезли map?

Map в каноническом виде(без индекса) тут впринципе не годится под решение этого куска, что в твоем for in цикле исходя из определения функции. Если там есть индекс, это тот же fold только в отдельно перегруженном врапере. Но можешь попробовать переписать на map и посмотреть какой вариант в конечном счете выйдет легче с фолдом или без него.

Map в каноническом виде(без индекса) тут впринципе не годится под решение этого куска, что в твоем for in цикле исходя из определения функции. Если там есть индекс, это тот же fold только в отдельно перегруженном врапере.

Почему мне приходится самому лазить в документации на язык, который ты пушишь?

Или сначала делаешь Seq.indexed, а потом Seq.map, или, внезапно, Seq.mapi

 let inputs = [ 10; 10; 10 ]

 inputs |> Seq.mapi (fun i x -> i + x)
Evaluates to a sequence yielding the same results as seq { 10; 11; 12 }
Но можешь попробовать переписать на map и посмотреть какой вариант в конечном счете выйдет легче с фолдом или без него.
fn get_sort_key(s: &str) -> Vec<SortKeyPart> {
    let parts: Vec<_> = s.split("\\").collect();

    let parts_count = parts.len();

    parts
        .into_iter()
        .enumerate()
        .map(|(i, p)| {
            if let Some(idx) = try_parse_index(p) {
                SortKeyPart::Index(idx)
            } else {
                if i < parts_count - 1 {
                    SortKeyPart::Key(p)
                } else {
                    SortKeyPart::FinalKey(p)
                }
            }
        })
        .collect()
}

спасибо, что примерами подкрепил то, что я тебе написал перед этим.

Если там есть индекс, это тот же fold только в отдельно перегруженном врапере.

Немного поправлю, если интересно.

Логически enumerate + map + collect (или Select(i, element) + ToList в дотнете) могут быть реализованы через fold, и стороннему обозревателю это может выглядеть как «отдельно перегруженный враппер».

IRL особенности реализации более сложные, остановлюсь на одной из них.

Использование map + collect (или их аналогов в других языках/библиотеках) позволяет сделать оптимизацию размера итогового вектора. Если выбираем элементы из коллекции с известным размером и вставляем новые элементы в вектор (ArrayList/etc), то заранее известно, что финальный размер ветора будет равен размеру исходной коллекции. Благодаря этому знанию, можно пре-аллоцировать размер финального вектора заранее, вместо того чтоб делать ре-аллокации и копирование данных в памяти пока он растет.

В .NET эти оптимизации реализованы и доступны «бесплатно» если юзать правильный интерфейс и не городить фигню:
github.com/...​ect.SpeedOpt.cs#L390-L419

Аналогичные оптимизации в Rust:

doc.rust-lang.org/...​c_from_iter.rs.html#58-61
doc.rust-lang.org/...​spec_extend.rs.html#28-36

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

let mut sort_key = vec![];
sort_key.push(key_part);

Дмитрий, смотри, я твою идею с fold взял и на ее основе уже запилил версию, которая не пушит — dou.ua/...​rums/topic/35446/#2277840. Сам fold мне не нравится, но твоя идея подтолкнула меня в нужном направлении. У меня корона с головы не упадет это признать, и делать улучшения на основе полученного фидбека.

Я вцелом надеюсь что веду разговор с адекватным собеседником, но это пока не точно.

Это как минимум делается с использованием константной памяти.

и вот такой вот непонятной хуитой

(0..n).fold((0, 1), |(n0, n1), _| (n1, n0 + n1)).0

Fixed

var sorted = str.Split("\n")
    .Select(s => new { Text = s.Trim(), SectionCount = s.Split("\\").Length })
    .OrderBy(t => t.SectionCount)
    .ThenBy(t => t.Text)
    .Select(t => t.Text)
    .ToArray();

У этих ключей общий префикс Comments\[0]\Childs\[1], они должни быть вместе

Aaa
Bbb
Cccc
Comments\[4]
Comments\[4]
Comments\[0]\Aaa
Comments\[0]\Bbb
Comments\[0]\Array\[0]
Comments\[0]\Array\[1]
Comments\[0]\Array\[4]
Comments\[0]\Array\[4]
Comments\[0]\Childs\[4]
Comments\[0]\Childs\[4]
Comments\[0]\Childs\[0]\Aaa
Comments\[0]\Childs\[0]\Bbb
Comments\[0]\Childs\[1]\Aaa
Comments\[0]\Childs\[1]\Bbb
Comments\[0]\Childs\[0]\Likes\[0]
Comments\[0]\Childs\[0]\Likes\[4]
Comments\[0]\Childs\[0]\Likes\[4]
Comments\[0]\Childs\[1]\Likes\[0]
Comments\[0]\Childs\[1]\Likes\[4]
Comments\[0]\Childs\[1]\Likes\[4]

если производительность не сильно важна, то проще всего можно сделать так:
public static void Main()
{
var strList = new List{ „Aaa”,
„Cccc”,
@"Comments\[0]\Bbb„,
„Bbb”,
@"Comments\[0]\Childs\[1]\Likes\[4]",
@"Comments\[0]\Aaa",
@"Comments\[0]\Childs\[0]\Likes\[4]",
@"Comments\[0]\Childs\[0]\Bbb",
@"Comments\[0]\Array\[0]",
@"Comments\[0]\Array\[1]",
@"Comments\[0]\Array\[4]",
@"Comments\[0]\Array\[4]",
@"Comments\[0]\Childs\[0]\Aaa",
@"Comments\[0]\Childs\[0]\Likes\[0]",
@"Comments\[0]\Childs\[0]\Likes\[4]",
@"Comments\[0]\Childs\[1]\Aaa",
@"Comments\[0]\Childs\[1]\Bbb",
@"Comments\[0]\Childs\[1]\Likes\[0]",
@"Comments\[0]\Childs\[1]\Likes\[4]",
@"Comments\[4]", @"Comments\[4]",
@"Comments\[0]\Childs\[4]",
@"Comments\[0]\Childs\[4]"
};
strList.Sort();
strList = strList.OrderBy(s=>s.Length).ToList();
}

мне лень переходить по ссылке

я если честно не понял зачем разбивать по пути?

static int CompareTo(string x, string y)
    {
        if (x.Length < y.Length)
        {
            var res = x.CompareTo(y.Substring(x.Length));
            return res == 0 ? -1 : res;
        }
        else if (x.Length > y.Length)
        {
            var res = x.Substring(y.Length).CompareTo(y);
            return res == 0 ? 1 : res;
        }
        else return x.CompareTo(y);
    }

Ну почти

Cccc
Aaa
Bbb
Comments\[0]\Aaa
Comments\[0]\Bbb
Comments\[0]\Childs\[0]\Aaa
Comments\[0]\Childs\[0]\Bbb
Comments\[0]\Childs\[1]\Aaa
Comments\[0]\Childs\[1]\Bbb
Comments\[0]\Childs\[0]\Likes\[0]
Comments\[0]\Childs\[0]\Likes\[4]
Comments\[0]\Childs\[0]\Likes\[4]
Comments\[0]\Childs\[1]\Likes\[0]
Comments\[0]\Childs\[1]\Likes\[4]
Comments\[0]\Childs\[1]\Likes\[4]
Comments\[0]\Childs\[4]
Comments\[0]\Childs\[4]
Comments\[0]\Array\[0]
Comments\[0]\Array\[1]
Comments\[0]\Array\[4]
Comments\[0]\Array\[4]
Comments\[4]
Comments\[4]

а, теперь понял что ты хочешь получить. Твой пример не очень удачный.

То есть нужно сортировать как при DFS, правильно?

Как-то так тогда

static int CompareTo(string x, string y)
    {
        if (x.Length < y.Length)
        {
            var res = x.CompareTo(y.Substring(0, x.Length + 1));
            return res == 0 ? -1 : res;
        }
        else if (x.Length > y.Length)
        {
            var res = x.Substring(0, y.Length+1).CompareTo(y);
            return res == 0 ? 1 : res;
        }
        else return x.CompareTo(y);
    }
я правда не очень понял почему в твоем примере

Comments\[0]\Bbb
должно идти перед
Comments\[0]\Array\[0]
В чем логика такой сортировки?

То есть такие строки ты ожидаешь в следующем порядке
Comments\[0]\Aaa
Comments\[0]\Bbb
Comments\[0]\Bbb\[0]
Comments\[0]\Array
Comments\[0]\Array\[0]

На мой взгляд в таком случае гораздо логичнее выглядит
Comments\[0]\Aaa
Comments\[0]\Array
Comments\[0]\Array\[0]
Comments\[0]\Bbb
Comments\[0]\Bbb\[0]

Забей. Я уже пофиксал. Сначала я пофиксал еще более мозго выносную задачу, с которой мне пришлось идти за ручкой и бумагой и все расписывать. А потом уже эту. А щас надо пойти прогуляться, в мозге осталось заряда на процентов 15

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

Молодец, хороший мальчик! :)

ого, DOU вже конкурує зі StackOverflow )

Ты не мог бы сформулировать задачу по-человечески? :) Опиши критерии сортировки так чтобы понятно было: «А < B если [первый критерий], [второй критерий если по первому паритет], ...».

Сформулировать четко задачу это уже почти решение :-)

Сформулировать на самом деле очень просто.
Живой джисон нарезается на ключи. Ключи пропускают через сортировку.
Потом ключи преобразовуют обратно в джисон. При обратном преобразовании структура джисона не должна быть разломана. Тоесть атрибуты типа
Title или Message могут менятся местами на своем уровне. А вот атрибуты
внутри Comments должни быть все вместе, иначе в джисоне окажется два атрибута Comments на одном уровне, что приведет к невалидному джисону

{
  "Title": "Hello everyone !",
  "Message": "Hello everyone in my article !",
  "OnDate": "",
  "IsApproved": true,
  "Comments": [
    {
      "Name": "Bob",
      "Message": "Hello from Bob",
      "Likes": ["Ted", "Jim", "John"],
      "Childs": [
        {
          "Name": "Ted",
          "Message": "Hello from Ted",
          "Likes": [ "Jim", "John", "Bob" ],
          "Childs": [
            {
              "Name": "Jim",
              "Message": "Hello from Jim",
              "Likes": [ "Bob", "Ted", "John" ]
            }
          ]
        },
        {
          "Name": "John",
          "Message": "Hello from John",
          "Likes": [ "Bob", "Ted", "Jim" ]
        }
      ]
    }
  ]

}
Ключи пропускают через сортировку

Нащо?
Якщо потрібно зберегти послідовність, то треба array використовувати

Нельзя, поскольку в array могут добавить новые ключи в конец и после сортировки они должни стать на свое место.

Зайду з іншого боку — js не зберігає послідовність keys
Якщо вам потрібна послідовність — ви зобов’язані використовувати array
Якщо вам треба з набору какі в вигляді декількох json з лівих ресурсів зробити когерентний json
То його логічніше зібрати в dict, а потім зробити з нього json без всякого сортування по key

И как из джисон сделать дикшинари ?

newtonsoft json вроде бы дает распарсивать json в dynamic, а dynamic это считай дикшинари

не стать, а встать. Почему эти два слова постоянно пктают

Как вариант ещё можно переписать на С++ должно работать чуть быстрее.

Ну да, пофиг что сортирует неправильно — зато быстрее же... :)

Сначала должни идти более короткие имена, потом более длинные

так а чому не спрацює спочатку порівнювати за довжинами і тільки якщо вони рівні, то проводити всі наступні процедури?

Потеряется порядок индексов тогда, они будут идти в перемешку

тобто, наприклад, Comments\[4] коротший за Comments\[0]\Childs\[4], але повинен йти після, бо у нього індекс більший. я правильно розумію?

Воообщем я пеереписал CompareTo так. И оно вроде работает уже в этом примере, но не работает в основном более сложном коде. Разбираюсь почему.

static int CompareTo(string x, string y)
        {
            var attr1 = x.Split('\\');
            var attr2 = y.Split('\\');

            //compare by path
            var countPath1 = attr1.Length;
            var countPath2 = attr2.Length;

            var minCountPath = Math.Min(countPath1, countPath2);

            for (ushort i = 0; i < minCountPath; i++)
            {
                var pathName1 = attr1[i];
                var pathName2 = attr2[i];

                if (pathName1 != pathName2)
                {
                    if (i < minCountPath - 1)
                    {
                        return pathName1.CompareTo(pathName2);
                    }
                    else
                    {
                        return countPath1.CompareTo(countPath2);
                    }
                }
            }

            return 0;
        }
Понятно, что самый очевидный способ отсортировать, это строить полноценное дерево с нодами и постепенно в него вставлять элементы, а потом обходить это дерево.

Функція вставки займе рядків 6 коду, функція обходу десь може 4. У тебе вже вдвічі більше коду і все ще не працює. Роби дерево.

примерно в том виде в котором он уже есть

Це не формальне визначення і якраз (мені) не зовсім зрозуміло як саме повинно бути відсортовано.

Ніколи не кодив на C# , але цей код не робить нічого, щоб Bbb було перед Array

Смысл такой что сначала идут более короткие имена, потом более длинные. Но они сгруппированы по пути который у них есть.

Тоесть условно, если взять группу. То понятно что у нее неправильная сортировка

Comments\[0]\Aaa
Comments\[0]\Array\[0]
Comments\[0]\Array\[1]
Comments\[0]\Array\[4]
Comments\[0]\Array\[4]
Comments\[0]\Bbb

должно быть

Comments\[0]\Aaa
Comments\[0]\Bbb
Comments\[0]\Array\[0]
Comments\[0]\Array\[1]
Comments\[0]\Array\[4]
Comments\[0]\Array\[4]

Тобто якби там було ще Arr, то порядок був би Aaa, Arr, Bbb, Array ?

Да, но при условие что у

Arr

нет чилдов

Підписатись на коментарі