Перетасовка массива Lua не работает

Я работал над сценарием для рандомизации данных внутри моего массива, но я получаю сообщение об ошибке

unexpected symbol near "#"

Когда я перехожу к этой строке и удаляю "#", я получаю

attempt to perform arithmetic on local `n' (a table value)

Вот моя функция перемешивания

function shuffle(array)
    local array = array
    local n = #array
    local j
    local random = math.random
    for i=n-1, 1, -1 do
        j = random(i)
        array[j],array[i] = array[i],array[j]
    end
    return array
end

и вот что я пытаюсь рандомизировать

shuffle(new_players)
for name,character in pairs(new_players) do
    if (character.inside == true and character.death == 0) then
        local player = getPlayerByName(name, map_copy)
        if (player ~= nil) then
            addState(player)
            break
        end
    end
end

Вот мой массив

new_players= { }
new_players[charName] = { death = 0, inside= true }

Любая помощь? Если я делаю что-то совершенно неправильно?


person Derick    schedule 15.06.2013    source источник
comment
Вы не можете перетасовать ассоциативный массив.   -  person Egor Skriptunoff    schedule 15.06.2013
comment
Почему break после addState? Вам нужен только один случайный игрок?   -  person Egor Skriptunoff    schedule 15.06.2013
comment
Почему у вас есть строка local array = array?   -  person derkyjadex    schedule 15.06.2013
comment
Какую версию Lua используете?   -  person lhf    schedule 15.06.2013
comment
@EgorSkriptunoff Да, нужен только один случайный игрок.   -  person Derick    schedule 15.06.2013
comment
@derkyjadex Разве этого не должно быть?   -  person Derick    schedule 15.06.2013
comment
@DerickJones Логически это ничего не делает. Я задавался вопросом, должна ли это быть какая-то оптимизация производительности, но array уже local. Так что, если я не ошибаюсь, он вообще ничего не делает.   -  person derkyjadex    schedule 16.06.2013
comment
@derkyjadex создает новую локальную переменную с именем array и присваивает ей значение array. Это избыточно, но кое-что сделает.   -  person dualed    schedule 16.06.2013


Ответы (2)


1) Попробуйте изменить charName со строки на число.

2) Для перемешивания вы можете использовать этот код:

function swap(array, index1, index2)
    array[index1], array[index2] = array[index2], array[index1]
end

function shuffle(array)
    local counter = #array
    while counter > 1 do
        local index = math.random(counter)
        swap(array, index, counter)
        counter = counter - 1
    end
end
person Dmi7ry    schedule 15.06.2013
comment
Использовать ли это после того, как я изменю charName со строки на число? Или не важно? - person Derick; 15.06.2013
comment
Как хочешь. В вашем коде есть странные вещи, такие как local array = array, которые способствуют неоднозначному поведению кода. Ваши и мои функции очень похожи, но моя читает лучше. P.S. Извините за гугл-перевод. - person Dmi7ry; 16.06.2013

Если ваша версия Lua < 5.1, то оператора # нет. Вместо этого используйте table.getn:

local n = table.getn(array);

(Обновление) Обратите внимание, что ваша функция, хотя она делает перетасовку элементов, на самом деле не перетасовывает все элементы. Кроме того, поскольку вы уменьшаете диапазон с каждой итерацией, вы почти наверняка будете менять местами первые 10% вашего массива несколько раз. Перестановка их несколько раз сама по себе неплоха, но для сравнения, вы почти никогда не меняете местами другие элементы.

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

function shuffle(array)
    local n, random, j = table.getn(array), math.random
    for i=1, n do
        j,k = random(n), random(n)
        array[j],array[k] = array[k],array[j]
    end
    return array
end

Другой вариант — выбрать случайные элементы из исходного массива и поместить их в новый выходной массив:

local rnd,trem,getn,ins = math.random,table.remove,table.getn,table.insert;
function shuffle(a)
    local r = {};
    while getn(a) > 0 do
        ins(r, trem(a, rnd(getn(a))));
    end
    return r;
end
person dualed    schedule 16.06.2013