РАБОТА С МАССИВАМИ_
SORT, INARRAYO, LENGTH(), COPY, JOIN, DELETE, CHAR$(), NUMBER()
SORT [INVERSE] < символьный масс ив {числовой массив|строка символов >
Этот оператор упорядочивает элементы числового
или символьного массива. Числовой массив должен быть одномерным,
символьный — либо одномерным, либо двухмерным (одномерный массив
символьных строк). В одномерном символьном массиве оператор SORT
расставляет символы (в массиве строк — строки) в алфавитном
порядке, точнее, в порядке возрастания кодов. Числовой массив
сортируется но значениям его элементов от большего к меньшему.
Конструкция SORT INVERSE сортирует элементы в обратном порядке.
SORT позволяет почти мгновенно отыскать максимальное и минимальное значения в числовом массиве:
10 DIM А( 100)
20 FOR k=1 ТО 100: LET A(k)=10*RND: NEXT k
30 SORT A(): LET Max=A(1): LET Min=A(100)
40 PRINT "Min=";Min, "Max=";Max
Еще интереснее использовать этот оператор с
символьными массивами. Здесь он открывает большие перспективы для
создания справочных систем и баз данных.
В символьной строке оператор SORT сортирует
символы; в массиве символьных строк переставляет строки, а порядок
символов в пределах каждой строки не изменяет. То есгь
последовательность строк в массиве становится подобной размещению слов
в словаре.
Сферу влияния оператора SORT можно ограничить заданным диапазоном строк с помощью сечения массива, например:
SORT А$(1 ТО 40)
Сортировать массив можно не только по первым
символам строк, но и по произвольному сечению, заданному во втором
измерении. К примеру, строка
SORT А$(1 ТО 40)(2 ТО)
отсортирует первые 40 строк массива, игнорируя их первый символ.
INARRAY(<массив строк>,<строка-образец>)
По многим свойствам эта функция напоминает
функцию INSTRING. Она возвращает номер элемента массива символьных
строк, в котором обнаружено первое включение <строки-образца>. На
элемент массива (строку), начиная с которой необходимо вести поиск,
указывает первый аргумент функции, например:
INARRAY(A$(20),"A")
Эта функция начнет поиск символа А с 20-го элемента массива (то есть с 20-й строки).
COPY <массив 1> ТО <массив 2>
JOIN < массив 1> ТО < массив 2 >
Оба оператора добавляют к <массиву 2> элементы <массива 1>. Оператор COPY копирует указанные элементы, сохраняя их в исходном массиве, a JOIN переносит, не сохраняя оригинал («сшивает» два массива). Поддерживается работа с одно- и двухмерными числовыми и символьными массивами.
Допустимо копировать массивы сами в себя.
Рассмотрим действие этих операторов на примере
работы с символьными строками и массивами строк. Операции с числовыми
массивами выполняются аналогично. В местах, где наблюдаются некоторые
различия, мы сделаем соответствующие оговорки.
10 LET A$="QWERTYUIOP": LET B$="qwertyuiop" 20 COPY A$ TO B$ 30 PRINT "A$=";A$, "B$=";B$
Эта небольшая программка выведет на экран: A$=QWERTYUIOP B$=qwertyuiopQWERTYU!OP
После замены в строке 20 оператора COPY на JOIN
выполнение программы прервется на 30-й строке сообщением Variable not
found — оператор JOIN ликвидирует переменную А$ после переноса ее
содержимого в переменную В$.
Заменим 20-ю строку на 20 COPY А$(4 ТО 6) ТО В$(3)
Результат станет таким:
A$=Q WERTYUIOP B$=qwRTYertyuiop
Применение оператора JOIN с такими же параметрами приведет к следующему:
A$=QWEUIOP B$=qwRTYertyuiop
Таким образом, сечение массива-источника (в
нашем случае А$(4 ТО 6)) задает фрагмент, подлежащий переносу или
копированию. Номер элемента, указанный в массиве-приемнике, (В$(3))
определяет место в нем, куда будет вставлен соответствующий фрагмент.
При работе с числовыми массивами также допустимо задавать их сечения, используя тот же синтаксис, что и с символьными массивами.
Операции копирования и переноса двухмерных
массивов более сложны. Для их анализа Вы можете написать специальную
программу. Мы же ограничимся приведением диаграмм, иллюстрирующих
работу операторов COPY и JOIN с массивами разных размеров и размерностей (рис. 24). На диаграммах представлены
массивы А() и В() (они могут быть как
числовыми, так и символьными), а также результаты выполнения оператора
COPY А() ТО В() или JOIN А() ТО В().
но т i=i то з 120 on i
LET Н5Ш LET »=37«
if тм<т тнел
LET a:12S2, Ph0IW=235 ELSE
LET 1=19.03, Phon«:242
131 ПЕХТ i
Рис. 21. Фрагмент листинга программы Beta Basic.
еееее| еввееI
j
1 AAA AAA
Г ввввв!
[ВВВВВ Аоооо I Аоооо IАоооо
А и В — элементы соответствующих массивов;
о — нулевое значение в числовом массиве или пробел — в символьном.
Рис. 24. Работа COPY и JOIN с двухмерными массивами.
Из этих диаграмм становится ясно, что в случае,
когда второе (либо единственное) измерение массива-приемника меньше
второго (либо единственного) измерения массива-источника,
массив-приемник играет роль «прокрустова ложа» —
пристраиваемый фрагмент или весь массив будет усечен по второй
размерности до границ своего нового пристанища (случаи 1 и 3).
Если же в новом жилище исходному массиву или
его фрагменту слишком просторно (второе измерение массива-приемника
больше, чем массива-источника), в этих случаях новые строки символьного
массива дополнятся пробелами. В числовых же массивах вместо недостающих
элементов будут сгоять нули (случаи 2 и 4).
Для всех вариантов применения оператора JOIN,
если не было указано сечение массива-источника, последний будет удален
из области переменных.
Синтаксис описываемых операторов допускает использование сечений только по первому измерению.
Как и случае одномерных массивов и символьных
строк, двухмерные массивы можно копировать или переносить не только в
конец массива-приемника, но и в любое другое его место.
DELETE <массив^символьная переменная)
Оператор удаляет из области переменных символьный или числовой массив либо, если задано сечение массива, его фрагмент. Он г1акже
работает с символьными и числовыми переменными, удаляя их из области
переменных. Действие оператора DELETE демонстрирует следующая программа:
10 DIM А(30,100)
20 DELETE А(11 ТО 20)
30 PRINT "A(";LENGTH(1 ,"A()");",";LENGTH(2,"A()");")"
Она напечатает: А(20,100), то есть оператор
DELETE при указании сечения сокращает массив по первому измерению. В
случае работы с символьными строками он позволяет вырезать из них
заданные фрагменты. При этом оператор DELETE С$(М ТО N) равносилен
строке LET С$=С$( ТО M)+C$(N ТО ).
Удаляя из программы переменные и массивы, отслужившие свой век, DELETE позволяет экономно расходовать память компьютера.
LENGTH!<измерение массива>,"<имя массива)")
Функция LENGTH определяет количество элементов
одно- или двухмерного массива (как символьного, так и числового) по
каждому его измерению. Номер измерения задается первым аргументом
функции, который может принимать значения 1 или 2. Имя массива
заключается в кавычки100:
10 DIM А(10,45)
20 PRINT LENGTH(1 ,"А()"), LENGTH(2,"A()")
В результате работы этого примера будут выведены два числа — 10 и 45.
Функция LENGTH позволяет работать с массивом,
размеры которого в данной точке программы неизвестны, без опасения
выйти за его пределы. Это может понадобиться в процедурах, где
универсальный алгоритм рассчитан на работу с массивами, в общем случае
имеющими разную длину. Например, программа сортировки элементов
одномерного массива (см. стр. 273) может быть переписана так:
10 DIM 0(100)
20 FOR k=1 ТО 100
30 LET G(k)=10*RND
40 NEXT k
SO PROC Limits G(),Emax,Emin
60 PRINT "Min=";Emin, "Max=";Emax 1000 DEF PROC
Limits REF F(), REF Max, REF Min 1010 LOCAL Lng,Q() 1020 LET
Lng=LENGTH(1/'F()") 1030 DIM Q(1)
1040 COPY F() TO Q(): DELETE Q(1) 1070 SORT INVERSE Q() 1080 LET Min=Q(1): LET Max=Q(Lng) 1090 END PROC
В начале этой программы при помощи генератора
случайных чисел формируется массив G() (причем размер массива может
быть произвольным), и ссылка на него передается в процедуру Limits
(строка 50). В ней вычисляется размер массива F() (процедура
«знает» массив G() только под этим именем; строка 1020) и
затем его содержимое копируется в массив Q() (строка 1040), объявленный
ранее как локальный (строка 1010). Далее идет сортировка (строка 1070)
и нахождение предельных значений (строка 1080) по старой схеме. По
выходу из процедуры не определенные ранее переменные Emax и Emin будут
иметь значения, которые получили в процедуре их alter ego —
переменные Мах и Min.
В завершение этого раздела мы расскажем о двух
функциях, также позволяющих значительно экономить память при работе с
целочисленными массивами:
CHAR$(< число >)
NUMBER (< двухсимвольная переменная >)
Как известно, под хранение любого числа в
памяти ZX Spectrum отводится 5 байтов, в то время как для представления
целого числа из интервала 0...65535 достаточно только двух. Поэтому
целочисленные массивы преимущественно «хранят воздух»
— на Vs они заполнены нулями. Бороться с такой непозволительной
роскошью помогает функция CHARJ: она представляет числа из интервала
0...65535 двухбайтовыми строками, то есть равносильна следующему набору
инструкций:
LET A=INT (N/256): LET B=N-A*256 LET D$=CHR$ A+CHR$ B
- где N — целое число из указанного диапазона.
Функция NUMBER() производит обратную операцию
— переводит двухсимвольные строки в форму целых чисел. Аналогом
функции является строка:
LET N=256*CODE D$(1)+CODE D$(2)
Ниже мы приводим пример, демонстрирующий экономию памяти, достигаемую с помощью этих функций:
10 DIM D$(500,2)
20 FOR К=1 ТО 500
ВО LET D$(K)=CHAR$(K): NEXT К
40 PRINT МЕМ()
50 DIM N(500)
60 FOR K=1 TO 500
70 LET N(K)=NUMBER(D$(K))
80 NEXT K: DELETE D$()
90 PRINT MEM()
В первом цикле программы с помощью функции
CHAR$ из целых чисел от 1 до 500 формируется символьный массив (строки
10...30), после чего на экран выводится количество памяти в байтах,
доступной для бейсик-программ (строка 40). Во втором цикле (строки
60...80) функция NUMBER переводит символьный массив в числовой. После
удаления символьного массива снова печатается объем свободной памяти.
Анализируя результат, можно сделать вывод, что для целочисленного
массива размером лишь в 500 элементов преобразование его в двухбайтовое
представление дает экономию в полтора килобайта.
РАБОТА С КЛАВИАТУРОЙ_
EDIT, GET
Помимо описанных выше средств программного
преобразования символьных строк, Beta Basic позволяет вручную
редактировать строковые, а также и числовые данные. Делается это с
помощью оператора EDIT, уже знакомого по описанию редактора Beta Basic.
В новом амплуа он имеет следующий синтаксис:
EDIT [LINE] < символьная переменная> | < числовая переменная >
По действию оператор EDIT близок к INPUT
— он присваивает переменной, указанной следом за ним,
соответственно символьное или числовое значение, введенное с
клавиатуры. Но в отличие от INPUT, он не отнимает у переменной ее
прежнего содержимого, а выводит его в строку служебного экрана для
редактирования. Вот небольшой пример:
10 LET A$="QWERTY", B$="qwerty" 20 INPUT "A$="; LINE A$, 30 EDIT "B$="; LINE B$ 40 PRINT "A$=";A$,"B$=";B$
Если при выполнении, этой программки на запросы
обоих операторов просто нажать клавишу Enter, то PRINT (строка 40)
«покажет», что переменная А$ «опустошилась», а
В$ сохранила ранее присвоенное ей значение. Поместив перед именем
переменной точку с запятой, можно организовать редактирование и
числовых переменных. Если стоящая в EDIT переменная не была к этому
моменту определена, то оператор EDIT будет работать как обычный INPUT.
В списке из нескольких переменных для всех из них, кроме первой, EDIT
тоже работает как INPUT.
Недопустимо подсовывать оператору EDIT
«пустую строку» — это может привести к сбросу или
зависанию компьютера. Поэтому перед применением EDIT в программе (если
нет уверенности) рекомендуется делать проверку неременной на
«пустоту»:
IF А$="" THEN INPUT А$: ELSE EDIT А$
GET < символьная переменная {числовая переменная >
Оператор GET производит опрос клавиатуры и
присваивает переменной символьное или числовое (в зависимости от того,
какая переменна» используется в качестве параметра) значение,
соответствующее нажатой клавише, одной или в комбинации с
функциональными клавишами CS и SS На нажатие самих функциональных
клавиш GET не реагирует. В отличие от функции стандартного Бейсика
INKEY$, оператор GET задерживает выполнение программы и ждет, пока не
будет нажата клавиша. Он в некоторой степени аналогичен комбинации
PAUSE 0: LET A$=INKEY$
Кроме того, оператор GET позволяет менять
режимы курсора во время ожидания нажатия клавиши: он не реагирует на
нажатие комбинаций клавиш, задающих тот или иной тип курсора. Используя
это свойство, можно считывать символы, возвращаемые клавиатурой не
только в режимах курсора [L] или [С], как при работе с функцией INKEY$,
но и в режимах [Е] и [GJ.
Оператор GET с числовой переменной в качестве
параметра при нажатии цифровых клавиш в режимах курсора [LJ и [С]
присваивает ей, соответственно, значения от 0 до 9. При нажатии клавиши
А переменной присваивается значение 10, В — 11 и т. д. по
алфавиту.
Рассмотрим небольшой пример:
10 PRINT OVER 1 ;"_";CHR$ 8;: GET A$
30 PRINT OVER 1 ;"_";CHR$ 8;: 40 PRINT A$;
50 GO TO 10
Для такой крохотной программки результат
неожиданный и впечатляющий: теперь можно свободно перемещать курсор по
экрану и вводить символы и ключевые слова в люОом его месте. Чтобы
избежать сообщения invalid colour при попытке удалить символ клавишами
CS/0, находясь в режиме курсора [Е]*, целесообразно заменить 40-ю
строку программы на
40 IF CODE А$<16 OR CODE А$>31 THEN PRINT A$
Согласитесь, получившиеся пять строк —
неплохая заготовка для создания полноэкранного редактора программ Beta
Basic. Но вот проблема: как включить введенную строку в текст
программы? Beta Basic имеет решение и на этот случай: в нем
предусмотрен оператор KEYIN, который мы рас смотрим чуть позже.