Что нового

[Массивы] Концепция массивов, ее реализация в AutoIt -- базовое понимание

J

joytickus

Гость
Добрый день, уважаемые дамы и господа!

Коротко о главном:
Есть таблица из 1-5 строк и a-d столбцов с присутствующими данными в виде двоичных значений, меняющимися при получении данных на вход.
Как правильно оформлять двухмерный массив для этой таблицы: Dim $MyArray[4][5] = [[a, b, c, d], [1, 2, 3, 4, 5]]?
Как работать в дальнейшем с этим массивом? Как получать количество значений в определенных строках и/или столбцах? Какими командами?
Как обеспечить изменение значений в массиве не сторонними переменными с двоичным переключателем, а непосредственно в массиве?

последний раз касавшийся математики сложнее умножения в школе тринадцать лет назад. Программированием не занимался вообще никогда, а тут вдруг понадобилось написать для своих нужд программу, и воспользоваться я решил для этих целей AutoIt. Плотно изучил начальные концепции программирования в общем, синтаксис AutoIt, многое понял, что-то уже реализовал в коде (избретая велосипеды на каждом шагу :smile: ), но сейчас натолкнулся на неподъемную вещь -- массивы. Уже сутки копаюсь в справке, документации, форуме и других интернетах на предмет информации реализации массивов, но везде она представлена в виде для людей, уже понимающих основы. А я, похоже, самые основы и не понимаю.

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

Есть некоторое количество систематических элементов, которые складываясь вместе, образуют уникальные идентификаторы для элементов второго уровня. Для примера возьмем: числовой ряд от 1 до 5 и четыре буквенных обозначения -- a, b, с и d. Таким образом, элементы второго уровня будут иметь значения вида 1a, 3c, 9b и т.д. Они не повторяются, есть только этот набор из 20 элементов (5х4) В процессе деятельности эти элементы в рандомном порядке будут подаваться на вход в фиксированных порциях, например, по два элемента. Нужно определять, как между собой соотносятся эти элементы. Человек, глядя на набор [1c, 5d, 3a, 2c, 3c, 2a] видит, что в нем элементы имеют определенные сходства -- три цифры с буквой "с", по два раза повторяются цифры "2" и "3". Есть необходимость научить компьютер понимать то же самое и в соответствии с этим пониманием совершать какое-то действие.

Как я подошел к задаче:

Для начала ввел глобальные переменные, которые у меня имеют значения 0 и 1 ("флажки"), и соответствуют каждому из двадцати элементов. При вводе переменных они обозначены "0" Таким образом, когда программа получает на вход 2с, то меняет значение переменной "$2с" на "1": $2c = 1. В дальнейшем получается что в перечисленных двадцати переменных некоторые флажки "подняты" -- имеют значение не "0", а "1".

Поскольку эти элементы систематические, то их можно объединить в таблицу, в которой строкам будут соответсвовать, например, цифры, а столбцам -- буквы. И, если в эту таблицу поместить флажки, то будет видно, в чем сходны между собой наборы элементов. Например, из примера выше, будет видно, что в столбце "с" подняты флажки у элементов 1, 2 и 3, а в строках "2" и "3" подняты флажки у двух элементов. И, например, если задать пороговое значение для однотипных элементов 3, то в первом случае программа выполнит нужное действие, например, выведет сообщение.

Дальше в сомнениях:

Сначала подошел к вопросу методом перебора (копи-пейст никто не отменял), логично посчитав, что компьютер не человек и способен совершать операции гораздо быстрее. И для определения первых двух элементов (а всего их больше сотни), перебрать возможные комбинации вполне реально, тем более что есть неплохой оператор Select...Case...EndSelect. (К слову, программа получилась на 35000 строк, но работала исправно :smile: ). Но когда количество элементов увеличилось, я понял, что тону.

Тут я и задумался о таблице. Когда начал копать более подробно, обнаружил, что есть концепция массивов. Сама концепция понятна -- по сути, это и есть таблица, заданная определенными операторами с определенными значениями. Но вот как ее задать в коде, и главное, как потом научить программу с этим работать?

Мои предположения:

Есть возможность задать переменную в виде массива, а если указывать определенные значения, то массив получится двухмерный.

Насколько я нашел:
Dim [Const] $array[subscript 1]...[subscript n] [ = initializer ]
где
initializer -- The value that will be initially assigned to the variable. A Const must include the initializer. The initializer can be a function call.

Вопросы:
Непонятно, как задать нужные мне параметры -- Dim $MyArray[5][4]?
Какова роль "инициализатора" и как он правильно вписывается в мой пример строкой выше? (пояснение из справки НЕ уложилось у меня в голове после сотого прочтения)
Как в коде в дальнейшем реализовать превышение порогового значения для некоторых элементов в строке или столбце?
Как реализовать выборку нужных значений из таблицы? (Например, если значений "3" два из четырех возможных, то нужно указать, какие именно присутствуют.)
Да и просто как запрашивать, какие "флажки" подняты?

PS: Если что-то не так с созданной темой, то прошу указать мне, что нужно исправить.
PPs: При ответах прошу учитывать возможное непонимание основных концепций автором темы и, по возможности, отсылать к нужным понятиям и терминам для поиска информации.
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
joytickus
без обид, но я не осилил такой объем текста, тем более в данном разделе. на будущее, если ты хочешь получать ответы на насущные вопросы, старайся обойтись без воды, есть задача, есть результат, который является решением задачи, если некие наработки и есть затык. четко, коротко, точно.

вопрос к другим модераторам (пусть хоть и других разделов) и администраторам:
не кажется ли вам, что тема больше подходит в раздел общения?
 
Автор
J

joytickus

Гость
Kaster,
я изменил тему, изложив суть вопроса и спрятав под спойлер полный вариант с деталями.
Так лучше?
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
joytickus,
Честно говоря, не совсем понял конечную цель.
Пример использования трех-мерного массива:
Код:
#include <Array.au3>

$sStringControl = '' ;строка, куда будем добавлять использованные элементы.
$sStringDigit = '0123456789' ;все цифры.
$sStringLetter = 'abcdefghijklmnopqrstuvwxyz' ;все буквы.
$iCountUniq = 0 ;счетчик уникальных значений.
$iCountRe = 0 ;счетчик повторов значений.

$aTempDigit = StringSplit($sStringDigit, '');временный массив цифр.
_ArrayDisplay($aTempDigit, 'цифры');смотрим, что получили.
$aTempLetter = StringSplit($sStringLetter, '');временный массив букв.
_ArrayDisplay($aTempLetter, 'буквы');смотрим, что получили.
#cs
	Создаем трех-мерный массив в котором:
	[0][0][0] - кол-во используемых строк;
	[0][0][0] - кол-во используемых столбцов;
	[1-n][1-n][0] - значения вида 0a - 9z;
	[1-n][1-n][1] - состояние элементов [1-n][1-n][0]. 0 - не использовали; 1 - использовали.
#ce
Dim $aArray[$aTempLetter[0] + 1][$aTempDigit[0] + 1][2] = [[[$aTempLetter[0], $aTempDigit[0]]]]
;заполняем массив:.
For $i = 1 To $aTempLetter[0]
	For $j = 1 To $aTempDigit[0]
		$aArray[$i][$j][0] = $aTempDigit[$j] & $aTempLetter[$i]
		$aArray[$i][$j][1] = 0
	Next
Next
;обнуляем временные массивы.
$aTempDigit = 0
$aTempLetter = 0
; в бесконечном цикле генерируем случайные значения вида 0a - 9z, ищем их в массиве и проверяем, видели мы их раньше или нет.
; в MsgBox: ОК - смотрим дальше; Отмена - выход из цикла.
While 1
	$sSearch = Random(0, 9, 1) & Chr(Random(97, 122, 1)) ;цифры 0-9 и буквы a-z
	;удаляем из случайного значения все цифры и, по номеру вхождения в $sStringLetter оставшейся буквы определяем номер строки в массиве.
	$iX = StringInStr($sStringLetter, StringRegExpReplace($sSearch, '[0-9]', ''))
	;удаляем из случайного значения все, кроме цифр, и, по номеру вхождения в $sStringDigit оставшейся цифры определяем номер колонки в массиве.
	$iY = StringInStr($sStringDigit, StringRegExpReplace($sSearch, '[^0-9]', ''))
	;проверяем, использовали уже это значение или нет.
	If $aArray[$iX][$iY][1] Then
		;использовали
		Beep(250, 50)
		$iCountRe += 1;увеличиваем счетчик повторов значений на 1.
		If MsgBox(65, $sSearch, 'X = ' & $iX & ' Y = ' & $iY & @LF & 'Значение = ' & $aArray[$iX][$iY][0] & @LF & 'Уже видели') = 2 Then ExitLoop
	Else
		;не использовали.
		;добавляем к строке только использованное значение
		$sStringControl &= $aArray[$iX][$iY][0] & '|'
		;присваиваем элементу [1-n][1-n][1] значение 1, т.е. уже видели
		$aArray[$iX][$iY][1] = 1
		$iCountUniq += 1;увеличиваем счетчик уникальных значений на 1.
		If MsgBox(65, $sSearch, 'X = ' & $iX & ' Y = ' & $iY & @LF & 'Значение = ' & $aArray[$iX][$iY][0] & @LF & 'Первый раз смотрим') = 2 Then ExitLoop
	EndIf
WEnd
;смотрим использованные значения:
MsgBox(64, 'Info', $sStringControl & @LF & @LF & 'Уникальных: ' & $iCountUniq & @TAB & 'Повторов: ' & $iCountRe)
;или в виде массива:
$aControl = StringSplit(StringTrimRight($sStringControl, 1), '|')
_ArrayDisplay($aControl, 'Смотрели:')


Kaster [?]
не кажется ли вам, что тема больше подходит в раздел общения?
ИМХО, согласен.
 
Автор
J

joytickus

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

madmasles
Судя по комментариям в коде -- это то, что мне нужно. Сейчас буду медитировать над самим кодом -- много нового для меня.

Конечная цель: для наглядности попробую привести пример с фишками домино -- они имеют по два значения, собраны в определенной последовательности и присутствуют в наборе в единственном числе. Те фишки, что еще не отыграли -- мы их не видим, они для нас "0", те, что уже выложены на стол и находятся в руке -- они нам видны, и они для нас "1". Таким образом, глядя на "1"-фишки, можно понять, какие еще находятся в состоянии "0", учитывая, что их конечное число. Надо научить этому программу.

Спасибо за ваше участие! По результатам отпишусь в теме, надеюсь, с готовым кодом. ))

Тему, если нужно, перенесите. Я так понял, я этого сделать не могу. Во всяком случае, не нашел.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Самая распространенная ошибка при использовании массивов - копание в сторону трех- и более мерных массивов. Поверьте, в 99% они вам не понадобятся, только лишь введут в заблуждение.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
Yashied [?]
Самая распространенная ошибка при использовании массивов - копание в сторону трех- и более мерных массивов.
Согласен. :smile:
Я просто привел пример использования 3-х мерного массива, может быть, не совсем удачный, другого не придумал. :smile:
Вот то же самое, что и в первом примере, но вообще без массивов:
Код:
#include <Array.au3>

$sStringControl = '|' ;строка, куда будем добавлять использованные элементы.
$iCountUniq = 0 ;счетчик уникальных значений.
$iCountRe = 0 ;счетчик повторов значений.

; в бесконечном цикле генерируем случайные значения вида 0a - 9z и проверяем, видели мы их раньше или нет.
; в MsgBox: ОК - смотрим дальше; Отмена - выход из цикла.
While 1
	$sSearch = Random(0, 9, 1) & Chr(Random(97, 122, 1)) ;цифры 0-9 и буквы a-z
	;проверяем, использовали уже это значение или нет.
	If StringInStr($sStringControl, '|' & $sSearch & '|') Then
		;использовали
		Beep(250, 50)
		$iCountRe += 1;увеличиваем счетчик повторов значений на 1.
		If MsgBox(65, $sSearch, 'Уже видели') = 2 Then ExitLoop
	Else
		;не использовали.
		;добавляем к строке только использованное значение
		$sStringControl &= $sSearch & '|'
		$iCountUniq += 1;увеличиваем счетчик уникальных значений на 1.
		If MsgBox(65, $sSearch, 'Первый раз смотрим') = 2 Then ExitLoop
	EndIf
WEnd
;смотрим использованные значения:
MsgBox(64, 'Info', $sStringControl & @LF & @LF & 'Уникальных: ' & $iCountUniq & @TAB & 'Повторов: ' & $iCountRe)
;или в виде массива:
$aControl = StringSplit(StringTrimLeft(StringTrimRight($sStringControl, 1), 1), '|')
_ArrayDisplay($aControl, 'Уникальные:')
 
Автор
J

joytickus

Гость
В общем, помедитировав над кодом и поняв, что это не совсем то, что мне нужно, я придумал, как обойтись без массивов. Натолкнула меня на эту мысль идея счетчиков, которую я увидел в обоих примерах уважаемого madmasles'а. Почему не совсем то -- входные данные не просто в виде 1а, а в виде уникальных шести- или семизначных чисел, которые я прописываю в начале константами. А проверки и действия я решил сделать простым перебором, но при этом разделив входные данные и подсчитывая схожие значения. Вот примерная структура кода, как она у меня получилась:
Код:
While ; бесконечный цикл до сбоя или ручного прерывания
	While _startcondition <> _startnumber ; ожидание ввода информации
		Sleep(1000)
	WEnd
	_count1 ; считаем...
	_count2
	Select
		Case _condition1 ; условие, не требующее проверки
			_action9
		Case _condition2 ; условие, при котором проверяем и выполняем заданные действия
			_lettercheck
			_digitcheck
		Case Else
			MsgBox(0, "", "something's whrong"
			ExitLoop
	EndSelect
WEnd
Func _count1()
	Select ; подсчет цифровых значений первого входящего элемента
		Case $t11 = $5
			Global $5 += 1
		Case $t11 = $4
			Global $4 += 1
		Case $t11 = $3
			Global $3 += 1
		Case $t11 = $2
			Global $2 += 1
		Case $t11 = $1
			Global $1 += 1
		Case Else
			MsgBox(0, "", "can't read 1"
	EndSelect
	Select ; подсчет буквенных значений первого входящего элемента
		Case $t12 = $a
			Global $acount += 1
		Case $t12 = $b
			Global $bcount += 1
		Case $t12 = $c
			Global $ccount += 1
		Case $t12 = $d
			Global $dcount += 1
		Case Else
			MsgBox(0, "", "can't read 2"
	EndSelect
EndFunc
Func _count2()
; здесь и далее идут аналогичные функции для подсчетов цифровых и буквенных значений для второго входящего элемента, третьего и т.д.
EndFunc
Func _lettercheck() ; по результатам буквенных счетчиков выполнение определенных действий (если не попадаем в нужные значения, то не делать ничего)
	Select
		Case $acount = 4 Or $bcount = 4 Or $ccount = 4 Or $dcount = 4
			_action1
		Case $acount = 3 Or $bcount = 3 Or $ccount = 3 Or $dcount = 3
			_action2
	EndSelect
EndFunc
Func _digitcheck() ; по результатам цифровых счетчиков выполнение определенных действий (если не попадаем в нужные значения, то не делать ничего)
	Select
		Case $1 > 3 Or $2 > 3 Or $3 > 3 Or $4 > 3 Or $5 > 3
			_action1
		Case $1 = 3 Or $2 = 3 Or $3 = 3 Or $4 = 3 Or $5 = 3
			_action3
		Case $1 = 2 Or $2 = 2 Or $3 = 2 Or $4 = 2 Or $5 = 3
			_action4
	EndSelect
EndFunc
Func _action1
EndFunc
Func _action2
EndFunc
Func _action3
EndFunc
Func _action4
EndFunc
Func _action9
EndFunc


Вопрос: существуют ли функции или операторы, которые могут оптимизировать такой код? Или он достаточно оптимален?

PS: А тему и правда стоит перенести в "общение".
 

valldar

Новичок
Сообщения
32
Репутация
2
Подниму ка тему
Код:
Local $0=[1,2,3] ; не работает ERROR: syntax error
Local $0[1,2,3] ; не работает ERROR: syntax error

Local $0[3]=[1,2,3] ; работает

Почему этот параметр $0[3] является обязательным?
А что делать, если я вставляю в код массив из 100500 элементов методом копипасты, я получается должен их все пересчитать вручную, чтобы объявить количество строк?

Я понимаю, что можно сделать вот так
Код:
$string='1,2,3'
$array=StringSplit($string, ',')

Но все же, хотелось бы иногда обходится без лишнего кода.
 

darkwhite

Знающий
Сообщения
129
Репутация
5
joytickus чтобы понять принцип действия массивов надо понять длян начала - хоть немного теорию множеств

valldar
Почему этот параметр $0[3] является обязательным?
потому что, в объявлении массива в квадратных скобках стоит его размерность, а затем через знак равно его значения, конкретно для каждого элемента.
в первых случаях вы вообще не понять какой тип данных объявили
А что делать, если я вставляю в код массив из 100500 элементов методом копипасты, я получается должен их все пересчитать вручную, чтобы объявить количество строк?
например так
Код:
Dim $0[100500]

вот и объявили массив из 100500 элементов, но каждый их них пуст.
как его заполнять решать конкретно вам в конкретной задаче
 

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
valldar
Можно изменять размер массива динамически

Код:
#include <Array.au3>

Dim $aArray[1]

For $i = 0 To 100
	$aArray[0] += 1 
	ReDim $aArray[UBound($aArray) + 1] ; меняем размер массива на 1
	$aArray[UBound($aArray) - 1] = $i  ; записываем число в новую ячейку
Next

_ArrayDisplay($aArray)

MsgBox(0, '', 'Размер массива: ' & $aArray[0])
 

valldar

Новичок
Сообщения
32
Репутация
2
вот и объявили массив из 100500 элементов, но каждый их них пуст.
как его заполнять решать конкретно вам в конкретной задаче
нет, я имел в виду, стопицот ;D

Иногда мне приходится тупо вбивать в массив вручную много рандомных элементов (различные названия, числа и тп)
Код:
$array[??]=[dgeg,dsffe,dg,fhg,gd,f,dh,jxsf,sfwfs,fhg,sdegf,hthdca,fvdhthf,sfhj,czcdbfr,bcvsfs,gfnfc,vscsv,fncv xv,sxvx,bcbfnvc,xvdvdb,bfnfb,cscdb,bfxssv,cbvn,nv c,xvxbfbv,vxvdbc, bcdv,v,dbdbdv,dvdbd,bd]

И таких массивов штук 10
Попробуй сосчитай ;) тогда я точно ослепну, и так много за компом сижу)
Решений много можно придумать конечно, просто я подумал я чего-то не знаю об объявлении массивов
 

AZJIO

Меценат
Меценат
Сообщения
2,874
Репутация
1,194
valldar
Выдели текст и ищи запятые по выделенному; в Notepad++ есть кнопка "Подсчитать" (если скопировать массив в новый документ) или заменить в выделенном с последующей отменой (Ctrl+z). Можно сделать каждую ячеку в новой строке, тогда считаешь строки (слева колонка строк), или задаёшь с запасом и во временном цикле делаешь поиск первой пустой ячейки, в конце вывод в сообщение и Exit.
Как я понимаю массив в AutoIt3 это массив указателей, а не как нативный в C++ строка-массив, создающийся по длине букв.
 
Верх