powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / FoxPro, Visual FoxPro [игнор отключен] [закрыт для гостей] / Алгоритм для символьного типа
21 сообщений из 21, страница 1 из 1
Алгоритм для символьного типа
    #35164768
Alex Sith
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Исходная задача:
рассчитать количество записей таблицы, у которых в поле символьного типа значение попадает в заданный диапазон.

Особенность в том, что из-за символьного типа, например, пункт "85.3" > пункта "85.20".
Пример: мне надо посчитать количество записей для диапазона пунктов:
1) от п. "85.2" по "85.16.4" => BETWEEN(x,'85.2','85.16.4')
2) от п. "85.3" по "85.20.2" => BETWEEN(x,'85.3','85.20.2')

Примеры ошибок: в первый диапазон не попадает x="85.3", во второй не попадает x="85.8".

Уровень вложенности тройной, т.е. максимально длинным может быть пункт "99.99.99"

Как правильно производить подсчёт? Может уже есть готовая функция/алгоритм?(у меня поиск по форуму не работает)
...
Рейтинг: 0 / 0
Алгоритм для символьного типа
    #35164775
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
напиши функцию преобразования в число. Если максимум '99.99.99', то она должна такое давать:
"85.2" => 852000
"85.20.2" => 852020

а числа сравнивай.
...
Рейтинг: 0 / 0
Алгоритм для символьного типа
    #35164776
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T"85.2" => 852000
чуть ошибся, надо так
"85.2" => 850200
...
Рейтинг: 0 / 0
Алгоритм для символьного типа
    #35164779
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Число можно так получить:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
? GetNumber('85.3.1')

Func GetNumber
lpara tcValue
return val(GetParam(tcValue, '.',  1 )) *  10000  + val(GetParam(tcValue, '.',  2 )) *  100  + val(GetParam(tcValue, '.',  3 ))

* Выборка подстроки из строки с разделителями
* Параметры: Строка, Разделитель, Номер элемента
func GetParam
lpara lcText, lcDelim, lnNom
local lnPos, lcT
if lnNom <  1 
	lcT = ''
else
	if lnNom =  1 
		lcT = lcText
	else
		lnPos = at(lcDelim, lcText, lnNom- 1 )
		if lnPos #  0 
			lcT = substr(lcText, lnPos + len(lcDelim))
		else
			lcT = ''
		endif
	endif
	if at(lcDelim, lcT) #  0  
		lcT = left(lcT, at(lcDelim, lcT) -  1 )
	endif
endif
return lcT
...
Рейтинг: 0 / 0
Алгоритм для символьного типа
    #35164849
MiklS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
УУУ! Как всё сложно!

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
*lnVar1="85.3"
*lnVar2="85.20.2"
LPARAMETERS lnVar1, lnVar2

lnVar1=VAL(PADR(STRTRAN(lnVar1, ".", ""),  6 , "0"))
lnVar2=VAL(PADR(STRTRAN(lnVar2, ".", ""),  6 , "0"))

CALCULATE CNT() FOR BETWEEN(VAL(PADR(STRTRAN(Table.Pole, ".", ""),  6 , "0")), lnVar2, lnVar1) TO nCol
? nCol
Пользуйтесь!
...
Рейтинг: 0 / 0
Алгоритм для символьного типа
    #35164864
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MiklSУУУ! Как всё сложно!
УУУ! Как все неправильно!
...
Рейтинг: 0 / 0
Алгоритм для символьного типа
    #35164884
MiklS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
И что не работает?
...
Рейтинг: 0 / 0
Алгоритм для символьного типа
    #35164892
MiklS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ЗЫ! Сам только что проверил на курсоре - всё отлично работает!!!!!!!
...
Рейтинг: 0 / 0
Алгоритм для символьного типа
    #35164898
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MiklSЗЫ! Сам только что проверил на курсоре - всё отлично работает!!!!!!!
Отлично от того как надо.
По постановке задачи 85.2 < 85.16 А у тебя что получается?
...
Рейтинг: 0 / 0
Алгоритм для символьного типа
    #35164928
MiklS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Просто нужно вставить ALLTRIM() для переменных и Pole1. И всё. У меня в курсоре данные в виде 99.99.99. А ты пишешь 85.16!!
lnVar2=VAL(PADR( ALLTRIM( STRTRAN(lnVar2, ".", ""), 6, "0")))
Ну и далее по тексту.
...
Рейтинг: 0 / 0
Алгоритм для символьного типа
    #35164950
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MiklSУ меня в курсоре данные в виде 99.99.99. А ты пишешь 85.16!!
Хорош тормозить :)
Это вложенная нумерация (Раздел.Пункт.Подпункт) три целых числа через точку записанных в строку.
Вот и надо сравнивать сначала номера разделов, если разделы равны пунктов и т.д.
например BETWEEN(x,'85.2','85.16.4') означает в разделе 85 от пункта 2 по пункт 16 подпункт 2

Чтобы сравнивать как строки надо не точки убирать, а нули правильно добавлять:
"85.2" => "85.02.00", если точки убрать "850200" а у тебя "852000"
т.е. у тебя "85.2" равно "85.20"

Alex SithИсходная задача:
Пример: мне надо посчитать количество записей для диапазона пунктов:
1) от п. "85.2" по "85.16.4" => BETWEEN(x,'85.2','85.16.4')
2) от п. "85.3" по "85.20.2" => BETWEEN(x,'85.3','85.20.2')
Примеры ошибок: в первый диапазон не попадает x="85.3", во второй не попадает x="85.8".
...
...
Рейтинг: 0 / 0
Алгоритм для символьного типа
    #35165006
MiklS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ну если так "85.2" => "85.02.00" тогда ой! Может не правильно понял!!!
Тогда так
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
*lnVar1="85.3"
*lnVar2="85.20.2"
LPARAMETERS lnVar1, lnVar2

lnPar1=VAL(GETWORDNUM(lnVar1,  1 , "."))
lnPar2=VAL(GETWORDNUM(lnVar1,  2 , "."))
lnPar3=VAL(GETWORDNUM(lnVar1,  3 , "."))

lnPar21=VAL(GETWORDNUM(lnVar2,  1 , "."))
lnPar22=VAL(GETWORDNUM(lnVar2,  2 , "."))
lnPar23=VAL(GETWORDNUM(lnVar2,  3 , "."))
Ну и дальше через SCAN ... ENDSCAN
...
Рейтинг: 0 / 0
Алгоритм для символьного типа
    #35165019
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MiklS...
Код: plaintext
lnPar1=VAL(GETWORDNUM(lnVar1,  1 , "."))

Что я и сделал изначально. только GETWORDNUM() нет в 6-ке, потому и пользую самодельный GetParam()
...
Рейтинг: 0 / 0
Алгоритм для символьного типа
    #35165022
Sergey Sizov.
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dima T MiklS...
Код: plaintext
lnPar1=VAL(GETWORDNUM(lnVar1,  1 , "."))

Что я и сделал изначально. только GETWORDNUM() нет в 6-ке, потому и пользую самодельный GetParam()
Вместо него есть WordNum из Foxtools.fll
...
Рейтинг: 0 / 0
Алгоритм для символьного типа
    #35165035
MiklS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Вот так получается вроде правильно
*lnVar1="85.3"
*lnVar2="85.20.2"
LPARAMETERS lnVar1, lnVar2

lnPar1=PADL(GETWORDNUM(lnVar1, 1, "."), 2, "0")
lnPar2=PADL(GETWORDNUM(lnVar1, 2, "."), 2, "0")
lnPar3=PADL(GETWORDNUM(lnVar1, 3, "."), 2, "0")
lnVar1=VAL(lnPar1+lnPar2+lnPar3)
lnPar1=PADL(GETWORDNUM(lnVar2, 1, "."), 2, "0")
lnPar2=PADL(GETWORDNUM(lnVar2, 2, "."), 2, "0")
lnPar3=PADL(GETWORDNUM(lnVar2, 3, "."), 2, "0")
lnVar2=VAL(lnPar1+lnPar2+lnPar3)

CALCULATE CNT() FOR BETWEEN(VAL(PADR(STRTRAN(Table.Pole, ".", ""), 6, "0")), lnVar2, lnVar1) TO nCol
? nCol
...
Рейтинг: 0 / 0
Алгоритм для символьного типа
    #35165054
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MiklSВот так получается вроде правильно
...
Не-а. С Table.Pole то же самое проделать надо что и с lnVar1, lnVar2 (кстати префикс lc тут уместней)
и почему у тебя в BETWEEN() lnVar2, lnVar1 а не наоборот?

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
lcVar1="85.3"
lcVar2="85.20.2"

CALCULATE CNT() FOR BETWEEN(GetNumber(Table.Pole), GetNumber(lcVar1), GetNumber(lcVar2)) TO nCol
? nCol

func GetNumber
lpara tcVal
return VAL(PADL(GETWORDNUM(tcVal,  1 , "."),  2 , "0") + PADL(GETWORDNUM(tcVal,  2 , "."),  2 , "0") + PADL(GETWORDNUM(tcVal,  3 , "."),  2 , "0"))
...
Рейтинг: 0 / 0
Алгоритм для символьного типа
    #35165060
MiklS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Забыл переставить, просто скопировал....
...
Рейтинг: 0 / 0
Алгоритм для символьного типа
    #35165085
Фотография ВладимирМ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Для справки:

В VFP6 была введена функция ALINES(), при помощи которой можно выделить отдельные "слова". Правда, в VFP6 придется заменять символы-разделители на Chr(13)

Код: plaintext
1.
2.
3.
4.
5.
6.
LOCAL lcString, laElements( 1 ), lnI, lnTotal
lcString = "85.16.4"
lnTotal = Alines(laElements, ChrTran(m.lcString,".",Chr( 13 )))
FOR lnI= 1  TO lnTotal
	?m.lnI, laElements[m.lnI]
ENDFOR

Если, тем не менее, необходимо разбирать строку по символьно через поиск по AT(), то для упрощения анализа следует добавить в начало и конец анализируемой строки символ-разделитель.

Код: plaintext
1.
2.
3.
4.
5.
6.
LOCAL lcString, lcSeparator
lcSeparator = "."
lcString =  m.lcSeparator + "85.16.4" + m.lcSeparator

?"Начало первого элемента = ",AT(m.lcSeparator, m.lcString,  1 )
?"Конец  первого элемента = ",AT(m.lcSeparator, m.lcString,  2 )


Если разделителем выступает именно точка, то можно выделить фрагменты при помощи функций JustExt() и JustStem()

Хотя, разумеется, через GetWordNum() задача решается проще. Только, зачем же в число переводить? Ведь вы вместе и так получили корректную строку для сравнения.

Т.е. трансформировали строку вида "85.16.4" в строку "851604". А строку вида "85.2" в строку "850200". Последний шаг - первод в число - лишний. Все прекрасно будет работать и для символьных строк, поскольку они приведены в сопоставимый формат.
...
Рейтинг: 0 / 0
Алгоритм для символьного типа
    #35165093
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ВладимирМ Только, зачем же в число переводить? Ведь вы вместе и так получили корректную строку для сравнения.
Для понимания. Читабельности кода. Если реальный смысл строки - три целых числа записанных последовательно, так с числами и надо продолжать работать, я так думаю. За исключением случаев когда нужна максимальная производительность.
Изначально я предлагал вариант сориентированный на числа. Потом появился компромис с MiklS :)

Классические операции сравнения для строк это равно/неравно, а сравнение строк на больше/меньше - не частая операция с реальными строками.
...
Рейтинг: 0 / 0
Алгоритм для символьного типа
    #35165188
Kruchinin Pahan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T ВладимирМ Только, зачем же в число переводить? Ведь вы вместе и так получили корректную строку для сравнения.
Для понимания. Читабельности кода. Если реальный смысл строки - три целых числа записанных последовательно, так с числами и надо продолжать работать, я так думаю. За исключением случаев когда нужна максимальная производительность.
Изначально я предлагал вариант сориентированный на числа. Потом появился компромис с MiklS :)

Классические операции сравнения для строк это равно/неравно, а сравнение строк на больше/меньше - не частая операция с реальными строками.
Сам я единожды встречался с такой структурой хранения кода. Решения были разные для разных СУБД. В Фоксе пришлось оставить как есть, а для выборок ввести дополнительное поле, обновляемое по триггеру. Смысл поля в том, что в нем хранится значение уже расшарашенное по маске "XXX.XX.XX". При смене маски (которая лежит в отдельной настройке), поле пересчитывалось из исходных данных (в стиле "85.2.4"). Выборки при этом ходят достаточно быстро.
В Postgre я запихал маску в массив, пошаманил с сортировками, а для пользователя преобразую в текст. Так, как удобнее в данном случае (маскированно/или нет).
Но! Чтобы это более или менее шевелилось, пришлось написать свою функцинешку на сях в обоих случаях. А на сях реализуется со сложностью O(1).
...
Рейтинг: 0 / 0
Алгоритм для символьного типа
    #35165268
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Kruchinin Pahan[quot Dima T]Сам я единожды встречался с такой структурой хранения кода. Решения были разные для разных СУБД. В Фоксе пришлось оставить как есть, а для выборок ввести дополнительное поле, обновляемое по триггеру. Смысл поля в том, что в нем хранится значение уже расшарашенное по маске "XXX.XX.XX". При смене маски (которая лежит в отдельной настройке), поле пересчитывалось из исходных данных (в стиле "85.2.4"). Выборки при этом ходят достаточно быстро.
В Postgre я запихал маску в массив, пошаманил с сортировками, а для пользователя преобразую в текст. Так, как удобнее в данном случае (маскированно/или нет).
Но! Чтобы это более или менее шевелилось, пришлось написать свою функцинешку на сях в обоих случаях. А на сях реализуется со сложностью O(1).
Если задача критична к производительности (например объем данных очень большой) то предпочитаю хранить только удобную для программной обработки форму, а при выводе на клиенте преобразовывать в удобный пользователю вид. Так на сервер получается минимальная нагрузка и минимальный объем данных хранится. Как правило у клиента свободного процессорного времени больше.
...
Рейтинг: 0 / 0
21 сообщений из 21, страница 1 из 1
Форумы / FoxPro, Visual FoxPro [игнор отключен] [закрыт для гостей] / Алгоритм для символьного типа
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]