Модераторы: Poseidon
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Как отсортировать строки нужным мне образом? 
V
    Опции темы
ДЫМ
  Дата 26.6.2006, 01:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 224
Регистрация: 6.1.2004

Репутация: нет
Всего: 8



У меня есть список строк (если кому интересно, номера домов)

2
10
2а
1а
1
110
20
1б

Мне надо их отсортировать, чтобы список выглядел так

1
1а
1б
2
2а
10
20
110

Я знаю, что это возможно, потому что Total Commander, например, файлы с такими именами сорирует как мне надо, но метод TStringList.Sort выдает такой результат

1
10
110
1а
1б
2
20
2а


Как мне поступить? Подскажите, очень надо. 
PM MAIL WWW   Вверх
Демо
Дата 26.6.2006, 01:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 3.11.2005

Репутация: 2
Всего: 50



ДЫМ, 

Используй метод TStringList.CustomSort 


--------------------
    
PM MAIL ICQ Skype   Вверх
Poseidon
Дата 26.6.2006, 03:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Delphi developer
****


Профиль
Группа: Комодератор
Сообщений: 5273
Регистрация: 4.2.2005
Где: Гомель, Беларусь

Репутация: 5
Всего: 133



Использован алгоритм Вита

Код
function LPadCh(const S : string; Ch: Char; Len: Integer) : string;
 // Возвращает строку "добитую" символом Ch слева до длинны Len
var SLen : Integer;
begin
 Result := S;  SLen := Length(S);
 if Len <= SLen then  Exit;
 SetLength(Result,Len);
 if SLen > 0  then  Move(Result[1],Result[Succ(Word(Len))-SLen], SLen);
 FillChar(Result[1], Len-SLen, Ch);
end;

function IsInteger(const Value: string): Boolean;
var
  OutResult: Integer;
  Code: Integer;
begin
  Val(Value, OutResult, Code);
  Result := (Code = 0);
end;

function RPadCh(const S: string; Ch: Char) : string;
begin
  if not IsInteger(S[Length(s)])
  then Result:= '0' + s
  else Result:= s + Ch;
end;


function MyCompare (List: TStringList; Index1, Index2: Integer): Integer;
begin
 Result := CompareStr(RPadCh(LPadCh(List.Strings[Index1],'0',3),'_'),RPadCh(LPadCh(List.Strings[Index2],'0',3),'_'));
end;

procedure TForm1.Button1Click(Sender: TObject);
var h: TStringList;
i: integer;
begin
h:= TStringList.Create;

h.Add('2');
h.Add('10');
h.Add('2а');
h.Add('1а');
h.Add('1');
h.Add('110');
h.Add('20');
h.Add('1б');

h.CustomSort(MyCompare);

ShowMessage(h.Text);
end;


Код написан безобразно, т.к. уже 3 часа ночи smile Если что не понятно, то спрашивай. 


--------------------
Если хочешь, что бы что-то работало - используй написанное, 
если хочешь что-то понять - пиши сам...
PM MAIL ICQ   Вверх
ДЫМ
Дата 27.6.2006, 02:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 224
Регистрация: 6.1.2004

Репутация: нет
Всего: 8



Poseidon,  за ночную работу держи "плюсик", для моей задачи худо-бедно сгодится. Но вот не дает мне покоя Total Commander, как сортирует хорошо зараза, но как это делает - не понятно.

Ну скажите, как получить такой же порядок строк:

Строка №1
Строка №1а
Строка №1аб
Строка №2
Строка №10
Строка №20
Строка №110



или

1/1
1/2
1/10


Раз смогли авторы Total Commander`а, то ведь можно разгадать это? Или нет? 
 
PM MAIL WWW   Вверх
comtat
Дата 27.6.2006, 12:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1310
Регистрация: 2.5.2006
Где: Россия, Казань

Репутация: 8
Всего: 71



ДЫМ,
берешь строку выкидываешь из нее например "Строка №" и 
делаешь как в предыдушем примере
А потом при
Код

var str:string;
...
begin
str:='Строка №';
h:= TStringList.Create;

h.Add(str+'2');
....


Вот и все....  smile  


--------------------
Рожденный в СССР !!!
ExtJS - мой фреймворк 
PM   Вверх
ДЫМ
Дата 27.6.2006, 21:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 224
Регистрация: 6.1.2004

Репутация: нет
Всего: 8



Пример Poseidon не работает для набора 

1/1
1/2
1/10


да и вообще нужно что-то универсальное, а оно есть...  
PM MAIL WWW   Вверх
Akina
Дата 27.6.2006, 21:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 17
Всего: 454



Следует разделить строку на кванты и сортировать уже их.

Скажем строка 

Строка №1аб

делится на кванты

q1 = Строка №
q2 = 1
q3 = аб


и далее

order by q1 as string, q2 as integer, q3 as string

Аналогично строка 

1/10

делится на кванты

q1 = 1
q2 = /
q3 = 10

и далее

order by q1 as integer, q3 as integer
 


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
LesnoyChelovek
Дата 27.6.2006, 22:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


странник Интернета
**


Профиль
Группа: Участник
Сообщений: 346
Регистрация: 27.2.2006
Где: Русь

Репутация: 2
Всего: 10



Я вот думаю, что можно для сортировки использовать таблицу ASCII. ПОка не знаю как, но может додумаюсь, так код выложу.

Примерные набросок, смотрим число, после него встречаем букву и сравниваем ASCII код последующих букв. 


--------------------
Делай добро и бросай его в воду... оно не утонет.. добром к тебе вернеться.
http://picasaweb.google.com/LesnoyChelovek/Photo
PM MAIL   Вверх
ДЫМ
Дата 28.6.2006, 01:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 224
Регистрация: 6.1.2004

Репутация: нет
Всего: 8



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

А это что за строка? Напоминает SQL
order by q1 as string, q2 as integer, q3 as string

Если бы было все так просто. Мне надо на Delphi. 
PM MAIL WWW   Вверх
comtat
Дата 28.6.2006, 07:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1310
Регистрация: 2.5.2006
Где: Россия, Казань

Репутация: 8
Всего: 71



ДЫМ, у тебя фиксированные строки или произвольные ??
Цитата
А это что за строка? Напоминает SQL

Это и есть часть кода на SQL 


--------------------
Рожденный в СССР !!!
ExtJS - мой фреймворк 
PM   Вверх
ДЫМ
Дата 28.6.2006, 22:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 224
Регистрация: 6.1.2004

Репутация: нет
Всего: 8



Вопрос решен! 
Если кому-то интересно, решил написать как, потому что подобную проблему поднимали на форуме и тогда так и не нашли решения.
Понятно, что надо использовать StringList.CustomSort, я это подразумевал с самого начала, проблема как раз была в написании функции сравнения TListSortCompare. 
Логика такая: встречающиеся в строке числа добиваем нулями слева, чтобы они были одной разрядности, буквы и другие символы не трогаем, например:
строку:
Строка12Строка5
преобразуем в
Строка00012Строка00005
(в данном случае разрядность 5, с запасом)
потом сравниваем отформатированные строки


Код

//**********************
// Функция форматирования строки
// 
function fcGetFormattedString(sStr: string): string;
var i:Integer;
    sDigits:string;

begin
 sDigits:=''; Result:='';

 for i:=1 to Length(sStr)+1 do
 begin
  // выделяем из строки число
  if sStr[i] in ['0'..'9'] then
   begin
     sDigits:=sDigits+sStr[i];
   end
  else  // не цифры
   begin

    if sDigits<>'' then
     begin
      // добиваем текущее число нулями слева до 5
      Result:=Result+DupeString('0',5-Length(sDigits))+sDigits;
      sDigits:='';
     end;
     if sStr[i]<>#0 then Result:=Result+sStr[i];
   end;// не цифры

 end;//for
end;

//**********************
//  Функция сравнения для сортировки списка
//
function fcCompareItems(List: TStringList; Index1, Index2: Integer): Integer;
begin
 Result:=AnsiCompareText(
         fcGetFormattedString(List[Index1]),
         fcGetFormattedString(List[Index2]));
end;

Использование
Код

...
var List: TStringList;
begin
 List:= TStringList.Create;

 List.Add('Строка №2');
 List.Add('Строка №10');
 List.Add('Строка №20');
 List.Add('Строка №110');
 List.Add('1');
 List.Add('1/1');
 List.Add('1б');
 List.Add('2');
 List.Add('Строка №1а');
 List.Add('2а');
 List.Add('10');
 List.Add('20');
 List.Add('110');
 List.Add('1а/1');
 List.Add('1а/10');
 List.Add('1а/2');
 List.Add('Строка №1');
 List.Add('Строка №1аб');
 List.Add('1/2');
 List.Add('1/10');
 List.Add('1а');
 List.Add('1аб');

 List.CustomSort(fcCompareItems);

 ShowMessage(List.Text);
end;
...

На выходе получаем то что нам надо
1
1/1
1/2
1/10
1а
1а/1
1а/2
1а/10
1аб
1б
2
2а
10
20
110
Строка №1
Строка №1а
Строка №1аб
Строка №2
Строка №10
Строка №20
Строка №110



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

Это сообщение отредактировал(а) ДЫМ - 28.6.2006, 22:20
PM MAIL WWW   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Центр помощи"

ВНИМАНИЕ! Прежде чем создавать темы, или писать сообщения в данный раздел, ознакомьтесь, пожалуйста, с Правилами форума и конкретно этого раздела.
Несоблюдение правил может повлечь за собой самые строгие меры от закрытия/удаления темы до бана пользователя!


  • Название темы должно отражать её суть! (Не следует добавлять туда слова "помогите", "срочно" и т.п.)
  • При создании темы, первым делом в квадратных скобках укажите область, из которой исходит вопрос (язык, дисциплина, диплом). Пример: [C++].
  • В названии темы не нужно указывать происхождение задачи (например "школьная задача", "задача из учебника" и т.п.), не нужно указывать ее сложность ("простая задача", "легкий вопрос" и т.п.). Все это можно писать в тексте самой задачи.
  • Если Вы ошиблись при вводе названия темы, отправьте письмо любому из модераторов раздела (через личные сообщения или report).
  • Для подсветки кода пользуйтесь тегами [code][/code] (выделяйте код и нажимаете на кнопку "Код"). Не забывайте выбирать при этом соответствующий язык.
  • Помните: один топик - один вопрос!
  • В данном разделе запрещено поднимать темы, т.е. при отсутствии ответов на Ваш вопрос добавлять новые ответы к теме, тем самым поднимая тему на верх списка.
  • Если вы хотите, чтобы вашу проблему решили при помощи определенного алгоритма, то не забудьте описать его!
  • Если вопрос решён, то воспользуйтесь ссылкой "Пометить как решённый", которая находится под кнопками создания темы или специальным флажком при ответе.

Более подробно с правилами данного раздела Вы можете ознакомится в этой теме.

Если Вам помогли и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Poseidon, Rodman

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Центр помощи | Следующая тема »


 




[ Время генерации скрипта: 0.0564 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.