Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2002.02.21;
Скачать: [xml.tar.bz2];

Вниз

сортировка IP адресов и не только....   Найти похожие ветки 

 
Дремучий   (2002-01-24 17:45) [0]

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

1.2.4.
1.1.12.
1.2.
1.2.9.
9.2.3.2.
5.2.14.
11.
10.8.2.9.
12.3.1.

чтобы получить такой:

1.1.12.
1.2.
1.2.4.
1.2.9.
5.2.14.
9.2.3.2.
10.8.2.9.
11.
12.3.1.

для желающих разомять мозги - задачку усложню/упрощу
Реально как отсортировать таблицу по столбцу с такими данными
средствами (локального) SQL


 
Digitman   (2002-01-24 17:54) [1]

1. преобразуй каждый адрес в Intel DWORD и сортируй на здоровье любым алгоритмом сортировки целых чисел

2. алгоритм преобразования включи в UDF.


 
Дремучий   (2002-01-24 18:07) [2]

2 Digitman
есть маленькие нюансы
1) 1.2. < 1.2.4. и 1.2. < 11.
2) 1.1.12. < 11.

т.е. нужно учитывать уровень розряда и умножать число(макс двузначное) этого розряда на 10*НомерРозряда(1,2,... макс 4)
ЗАТЕМ ПРОПИСЫВАТЬ НАЙДЕНУЮ СУМУ УМНОЖЕННЫХ РОЗРЯДОВ В ОТДЕЛЬНОЕ
ПОЛЕ И ПО НЕМУ СОРТИРОВАТЬ.

1(4 розр).1(3 розр).12(2 розр). < 11(4 розр).

2 Digitman
так не получиться
1_1_12 > 11
правильно так
12*100+1*1000+4*10000 < 11*10000

А ЕСТЬ ЛИ МЕТОД ПОПРОЩЕ?


 
Chris   (2002-01-25 09:30) [3]

Можно попробовать такой вариант:

s1:="1.1.12.";
s2:="11.";
s1_:="";
s2_:="";
k:=0;
for i:=1 to length(s1) do
begin
if s1[i]="." then
begin
s1_:="."+FormatFloat("000",k)+s1_;
k:=0;
end;
else
k:=10*k+ord(s1[i])-48;
end;
k:=0;
for i:=1 to length(s2) do
begin
if s2[i]="." then
begin
s2_:="."+FormatFloat("000",k)+s2_;
k:=0;
end;
else
k:=10*k+ord(s2[i])-48;
end;

Теперь s1_=".012.001.001", а s2_=".011"
и теперь можно смело сортировать элементы.


 
Дмитрий   (2002-01-25 09:59) [4]

type
TIP = record
case byte of
0: (value: integer);
1: (fourthb, thirdb, secondb, firstb:byte);
end;

var ip: TIp;
ip.firstb = $FF;
..
ip.fourthb = 15;

// ip.value - это интегер. Сортитруй. Потом можешь преобразовать обратно


 
Johnmen   (2002-01-25 11:12) [5]

Пишешь свою UDF в MyDLL.dll типа (не забудь потом в БД сделать DECLARE EXTERNAL FUNCTION ...) :

function MySpicialSubstr(S: string; P: integer) : integer;
begin
try
Result:=StrToInt(ExtractWord(P,S,["."]));
except
Result:=0;
end;
end;

А потом смело выполняешь типа:

SELECT ipfield,
MySpicialSubstr(ipfield,1) AS F1,
MySpicialSubstr(ipfield,2) AS F2,
MySpicialSubstr(ipfield,3) AS F3,
MySpicialSubstr(ipfield,4) AS F4
FROM MyTable
ORDER BY F1, F2, F3, F4

(вышеописанное на уровне идеи)


 
Дремучий   (2002-01-25 12:24) [6]

спасибо всем откликнувшимся.
наиболее подходящий вариант для меня предложил Chris,
потому что во первых мне без разницы, как хранить значения
012.001.001 или 12.1.1
во вторых не потребуется дополнительных полей
в третьих наиболее подходящий вариант для локальной базы

eщe раз всем спасибо.

сие преобразование можно делать в событии OnAfterEdit, но...
а такой вопросик (наглею) можно ли написать UPDATE запрос
для перевода 12.1.11 -> 012.001.011



 
Digitman   (2002-01-25 13:18) [7]


uses WinSock;

type
EIPSpellCheckError = class(Exception);

const
IllegalIP = "Недопустимое строковое представление адреса : %s";

function ParseIp(Address: String; InAddr: PInAddr): Boolean;
var
PartNum, PartValue, PartCharNum, DelimiterCount: Integer;
psrc: PChar;
pdst: PByteArray;
NextChar: Char;
begin
Result:= False;
InAddr.S_addr:= 0;
PartNum:= 0;
PartCharNum:= 0;
PartValue:= 0;
DelimiterCount:= 0;
Address:= Trim(Address);
psrc:= PChar(Address);
pdst:= PByteArray(InAddr);
while psrc^ <> #0 do begin
NextChar:= psrc^;
case NextChar of
"0".."9":
if PartNum <= 4 then
if PartCharNum < 3 then begin
if DelimiterCount > 0 then
DelimiterCount:= 0
else if PartNum = 0 then
Inc(PartNum);
Inc(PartCharNum);
PartValue:= PartValue * 10 + byte(NextChar) - byte("0");
if PartValue > 255 then
Exit;
end else
Exit
else
exit;
".":
if DelimiterCount = 0 then
if PartNum > 0 then begin
pdst[PartNum - 1]:= Byte(PartValue);
PartValue:= 0;
Inc(PartNum);
PartCharNum:= 0;
PartValue:= 0;
Inc(DelimiterCount);
end else
Exit
else
Exit;
else
Exit;
end;
Inc(psrc);
end;
if PartNum > 0 then begin
if DelimiterCount = 0 then
pdst[PartNum - 1]:= Byte(PartValue);
Result:= True;
end;
end;


function CompareAddresses(List: TStringList; Index1, Index2: Integer): Integer;
var
InAddr: TInAddr;
Addr1, Addr2: DWord;
begin
if ParseIp(List[Index1], @inaddr) then
Addr1:= ntohl(InAddr.S_addr)
else
raise EIPSpellCheckError.CreateFmt(IllegalIP, [List[Index1]]);
if ParseIp(List[Index2], @inaddr) then
Addr2:= ntohl(InAddr.S_addr)
else
raise EIPSpellCheckError.CreateFmt(IllegalIP, [List[Index2]]);
if Addr1 > Addr2 then
Result:= 1
else if Addr1 < Addr2 then
Result:= -1
else
Result:= 0
end;

procedure Test;
var
AddrList: TStringList;
i, k: Integer;
s: string;
begin
AddrList:= TStringList.Create;
try
for i:= 0 to 9 do begin
s:= "";
for k:= 1 to Random(4) + 1 do
s:= s + IntToStr(Random(256)) + ".";
AddrList.Add(s);
end;
AddrList.CustomSort(@CompareAddresses);
s:= "";
for i:= 0 to AddrList.Count - 1 do
s:= s + AddrList[i] + #10;
ShowMessage(s);
finally
AddrList.Free;
end;
end;



Вызови процедуру Test(), она сгенерирует список из десятка строк, имитирующих список неких произвольных заданных тобой IP-адресов (в указанном тобой формате), отсортирует их и выведет окно с результатами сортировки


 
Дремучий   (2002-01-25 14:09) [8]

2 Digitman
написано в лучшем виде, въезжал правда медленно
новичком себя не считаю, но у тебя есть чему поучиться ;)
я так понял ты уже на том уровне, когда
сразу пишется оптимизированный код
Cool!


 
Digitman   (2002-01-25 14:36) [9]

>Дремучий
Ну, положим, он далеко не оптимизирован) Главная идея - отказаться от множества преобразований подстроки в число и наоборот, а также воспользоваться готовыми ф-циями, работающими с IP-адресами в разных представлениях. И если бы исходный массив у тебя был в полном корректном формате IP-адреса (XXX.XXX.XXX.XXX), парсер вообще можно было бы не использовать - все уже готово (см. хэлп на ф-цию inet-addr()) к преобразованию и сравнению : Intel_dword_addrvalue:= ntohl(inet_addr(string_addrvalue)).

А ты сразу в дебри полез с какими-то там "нюансами")... Нюанс один только - старайся поиметь на входе корректное строковое представление IP-адресов ... а все остальное "мягкие" и Борланд уже за тебя сделали))

Успехов)


 
Дремучий   (2002-01-25 16:06) [10]

2 Digitman
>>И если бы исходный массив у тебя был в полном корректном
>>формате IP-адреса (XXX.XXX.XXX.XXX)...
сортировка IP адресов и не только....

Дело в том, что данный список у меня не есть IP адреса,
а в действительности пункты файла отчетности, который хранится в парадоксовской таблице....
А про Ip я дописал, чтоб вопрос интересней звучал, и потому что это мне тоже вскоре нужно будет для айпи-сканера. Вот так два зайца пеоимел...
;)




 
Digitman   (2002-01-25 16:16) [11]

Если этот самый "файл отчетности" - твоей разработки, то это еще печальней. Глубоко сомневаюсь, что нельзя было при разработке структуры таблицы/запроса предусмотреть возможность форимрования подобного НД в целочисленных типах данных


 
Дремучий   (2002-01-25 17:27) [12]

суть такова, что пункты должны отображаться в определенной последовательности, т.е. должен быть индекс, по которому они сортируються. Из этого следует, что
1)что этот индекс не может быть по инкременту (добавление в середину)
2)требуется индекс (по полю понятному юзеру типа порядковый номер) - если использовать целочисельное поле, то оно по всей видимости будет не одно - разве это будет оптимальней?
3)если были два номера подряд 24 и 25 нужно вставить между ними
запись - вставка будет "более" проблематичной - хвост длиннее, чем в случае когда 2.4 и 2.5 вставляется запись
4)пункты в виде 2.4 и 2.5 все равно нужно выводить в таблице и на печать
5)возможность делать связку мастер-деталь по этому индексу(полю) с другими таблицами

в случае использования строкового поля подобного типа (по нему можно указывать местоположение строки в таблице) можно использовать только однин (первичный) индекс и это (одно)поле по
идее обеспечит возложенную на него функциональность.

интересно будет выслушать доводы за целочисельное поле(я) для решения подобной задачи.

С уважением Дремучий.



 
Digitman   (2002-01-25 18:04) [13]

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


 
Дремучий   (2002-01-25 18:33) [14]

2 Digitman © (25.01.02 18:04)
>>У тебя полный кавардак в терминологии
извини, заканчивал эк. вуз ;)
а объяснять-то и нечего

Table1 - таблица мастер - НД для отчета
xCode Char(12)
xName Char(100)
xSum Number


Table2 - таблица деталь - здесь храняться параметры по которым рассчитываются xSum (связь через xCode)
xCode Char(12)
xParam1 int
xParam2 int

задача 1 - обеспечить юзеру удобное добавление записей в
Table1(постановка добавленой записи на нужное место в базе),
записи Table1 либо в xCode либо в xName должны объязательно содержать кодировку в виде XX.XX.XX.XX

задача 2 - обеспечить удобный синтаксис выборки кусков НД
по заданому интервалу пунктов (от 2.1.1.0 до 3.9.9.9)

вот и все


 
Anatoly Podgoretsky   (2002-01-26 21:31) [15]

если с учетом применения для ИП адресов, то размерность должна быть 15 символов и преобразования при вводе/выводе для подавления/добавления незначащих нулей.
то есть хранишь в рормализованном виде XXX.XXX.XXX.XXX


 
Digitman   (2002-01-28 18:56) [16]

Таблицы твоей разработки ? Есть возможность добавить/изменить поля ?
Если есть, то:
- добавляешь в Table1 поле Integer, делаешь по нему уник.индекс по возрастанию; это будет PrimaryKey; поле code, в принципе, можно удалить : то, что в нем содержится, всегда можно получить из нового Integer-поляж
- изменяешь в Table2 поле Code на Integer, делаешь его индексированным; это будет ForeignKey;
- всякий раз при добавлении в Table1 записи преобразовываешь (в триггере, к примеру, или в SP) исх.строковое значение в формате XX.XX.XX.XX в Integer , например, парсером, код которого я привел (ну, с доработками, конечно); запись автоматически становится на свое место - об этом позаботится PK-индекс;
- при запросе к Table2 выполняешь обратное преобразование из Integer в char(12)

Вот и все !



Страницы: 1 вся ветка

Форум: "Базы";
Текущий архив: 2002.02.21;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.5 MB
Время: 0.004 c
3-66455
VladimirL
2002-01-28 17:18
2002.02.21
Фильтры и скорость


14-66660
IrviS
2001-12-31 20:59
2002.02.21
Что-то типа домино, но сложнее


3-66480
Vks
2002-01-28 14:42
2002.02.21
SQL запрос


7-66697
l@z@
2001-11-04 15:12
2002.02.21
Помогите! Необходимо, чтобы каждую секунду в лебел прибавлялось 5


3-66452
Laimer
2002-01-28 14:27
2002.02.21
QRepord





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский