Перемешивание массива [РЕШЕНО]

Автор raptor, 8 февраля 2011, 22:13

0 Пользователи и 1 гость просматривают эту тему.

raptor

Добрый вечер!
Есть массив, для простоты упорядоченный.
Типа A(i)=i, то есть А(1)=1, А(2)=2, ..., А(10)=10.
Нужно получить новый массив В, где элементы массива А() будут перемешаны случайно, то есть, например,
B(1)=15, B(2)=7, ..., В(10)=3.
Как это сделать с помощью макроса?
Спасибо.

PiVV

Проще не заморачиваться с двумя массивами, а перемешивать индексы единственного исходного.
P.S. Откуда в массиве B возьмётся элемент 15, если в исходном массиве самым большим было 10?

raptor

Прошу прощения, просто невнимательность.
Конечно, В(1)=5.

JohnSUN

Ничто не ново под луной...

[вложение удалено Администратором]
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

raptor


Рыбка Рио

#5
Можно перемешать индексы массива так:
REM  *****  BASIC  *****

Sub Main
N=9
M=N+1
Dim nm(N) As Long
   For j=0 to N
      nm(j) = j
   Next 'исходный массив
msgbox Join(nm(),",")
   For j=0 to N
      X = Int(M*rnd)
      v=nm(X)
      nm(X) = nm(j)
      nm(j)=v
   Next 'перемешанный
msgbox Join(nm(),",")
End Sub


А можно создать массив с нуля за 1 For-Next:
REM  *****  BASIC  *****

Sub Main
N=9
M=N+1
P=7 'взаимнопростое с N число, т.е. не имеют общих делителей
Dim nm(N) As Long
Dim cm(N) As Long
nm(0) = Int(M*rnd)
cm(nm(0)) = 1
   For j=1 to N
      v = 0
      X = Int(M*rnd)
      While v=0
         If cm(X)=0 then
            nm(j) = X
            cm(X) = 1
            v = 1
         else
            X = (X+P) mod M
         Endif
      Wend
   Next
msgbox Join(nm(),",")
End Sub
ubuntu 12.04 + LibO3.6.0

raptor

Всем большое спасибо!
РЕШЕНО.

Рыбка Рио

Вот макрос, который перемешает то что выделено:
Sub Main
Doc=ThisComponent
CS=Doc.CurrentSelection
If CS.supportsService("com.sun.star.sheet.SheetCellRanges") then CS=CS(0)
Ard=CS.DataArray
N = ubound(Ard())
M=N+1
Dim v
For j=0 to N
      X = Int(M*rnd)
      v=Ard(X)
      Ard(X) = Ard(j)
      Ard(j)=v
Next
CS.setDataArray(Ard())
End Sub


Можно было бы доделать и сделать расширение.
ubuntu 12.04 + LibO3.6.0

Рыбка Рио

Вот вариант, который работает с несколькими выделениями сразу (выделять несколько выделений - мышкой при нажатом Ctrl):

REM  *****  BASIC  *****

Sub Main
Doc=ThisComponent
CS=Doc.CurrentSelection
Dim ArCS(0)
If CS.supportsService("com.sun.star.sheet.SheetCellRanges") then
   CSn=CS.Count-1
   Redim ArCS(CSn)
   For i=0 to CSn
      ArCS(i)=CS(i)
   Next
Else
   CSn=0
   ArCS(0)=CS
Endif
Dim v
For i=0 to CSn
   Ard=ArCS(i).DataArray
   N = ubound(Ard())
   M=N+1
   For j=0 to N
         X = Int(M*rnd)
         v=Ard(X)
         Ard(X) = Ard(j)
         Ard(j)=v
   Next
   ArCS(i).setDataArray(Ard())
Next
End Sub
ubuntu 12.04 + LibO3.6.0

Рыбка Рио

Вот расширение, располагается в Calc, меню Сервис/Дополнения/Миксер (Tools/Add-ons/Mixer)

[вложение удалено Администратором]
ubuntu 12.04 + LibO3.6.0


Рыбка Рио

Есть всё же одна ошибка в макросе (в расширении тоже, сегодня исправлю). Дело в том, что изредка среди слуячайных числе возвращаемых функцией rnd могут появляться такие 0.9999999999999995 и ещё чуть больше - а это уже воспринимается как чистая единица, в результате Int(M*rnd)=M, и Basic пишеть ошибку что индекс превышен.

Sub Main
msgbox 0.999999999999999
msgbox 0.9999999999999999
End Sub


Поэтому можно заменить строчку M=N+1 на что-нибудь такое M=N+0.99.
ubuntu 12.04 + LibO3.6.0

Рыбка Рио

Можно использовать также внешний генератор случайных чисел - Mersenne Twister Random Number Generator Add-In | OpenOffice.org repository for Extensions.
Если расширение устновлено, то данный макрос будет использовать его для получения случайных чисел: (в следующей версии расширения я только закомментирую строчки с msgbox)

REM  *****  BASIC  *****

Sub Main
Doc=ThisComponent
CS=Doc.CurrentSelection
Dim ArCS(0)
If CS.supportsService("com.sun.star.sheet.SheetCellRanges") then
   CSn=CS.Count-1
   Redim ArCS(CSn)
   For i=0 to CSn
      ArCS(i)=CS(i)
   Next
Else
   CSn=0
   ArCS(0)=CS
Endif
Dim v
mt=CreateUnoService("mytools.math.MTRandom")
If IsNull(mt) then
msgbox "Используется встроенный генератор случайных числе"
   For i=0 to CSn
      Ard=ArCS(i).DataArray
      N = ubound(Ard())
      M=N+0.99
      For j=0 to N
            X = Int(M*rnd)
            v=Ard(X)
            Ard(X) = Ard(j)
            Ard(j)=v
      Next
      ArCS(i).setDataArray(Ard())
   Next
Else
msgbox "Используется Mersenne Twister Random Number Generator"
   For i=0 to CSn
      Ard=ArCS(i).DataArray
      N = ubound(Ard())
      For j=0 to N
            X = mt.randIntTo(N)
            v=Ard(X)
            Ard(X) = Ard(j)
            Ard(j)=v
      Next
      ArCS(i).setDataArray(Ard())
   Next
Endif
End Sub
ubuntu 12.04 + LibO3.6.0

bormant

#13
Int(0.9999999999999998) ещё 0, а Int(0.9999999999999999) уже 1   >:(
Автору на яд. Поддержать форум.

raptor