2009-09-11 6 views
25

ОРИГИНАЛЬНЫЙ ПОСТConcatenation таблиц в Lua

Учитывая, что нет встроенной функции в Lua, я в поисках функции, которая позволяет мне добавлять таблицы вместе. Я немного поработал в Google и пробовал все решения, которые я наткнулся, но ни один из них не работает должным образом.

Сценарий выглядит следующим образом: Я использую Lua, встроенную в приложение. Внутренняя команда приложения возвращает список значений в виде таблицы.

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


EDIT

Для тех, кто пришел на этот пост в будущем, обратите внимание на то, что @gimf вывешенным. Поскольку таблицы в Lua так же похожи, как и массивы, чем что-либо еще (даже в контексте списка), нет реального правильного способа добавления одной таблицы в другую. Ближайшей концепцией является слияние таблиц. Пожалуйста, см. Сообщение «Lua - merge tables?» за помощью в этом отношении.

+0

Возможные простофилю : http://stackoverflow.com/questions/1283388/lua-merge-tables. Вы упоминаете «рекурсивно в цикле». Вы ищете глубокое копирование + слияние? – gimpf

+0

Ниже перечислены ссылки, которые я нашел, что предлагаемые решения: http://ardoris.wordpress.com/2008/08/10/lua-merge-two-tables-awesome3-rc2-config/ http: // www.idevgames.com/forum/archive/index.php/t-10223.html Хотя я понимаю подход каждого из них, похоже, не работает. У вас есть рабочее решение? –

+0

gimpf, может быть, я не совсем понятен. Слияние таблиц и конкатенационных таблиц аналогичны, но очень разные. Я заинтересован в добавлении одной таблицы в другую, поэтому использование слова concatenate. –

ответ

2

Если вы хотите объединить две таблицы, но вам нужна глубокая копия таблицы результатов, по какой-либо причине используйте слияние с another SO question on merging tables плюс код глубокой копии от lua-users.

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

{ a = 1, b = 2 } 

сцепляются с другой таблицей

{ a = 5, b = 10 } 

должен результат

{ a = 1, b = 2, a = 5, b = 10 } 

, тогда вам не повезло. Ключи уникальны.

Кажется, что вы хотите иметь список пар, например { { a, 1 }, { b, 2 }, { a, 5 }, { b, 10 } }. Вы также можете использовать конечную структуру, например { a = { 1, 5 }, b = { 2, 10 } }, в зависимости от вашего приложения.

Но простое представление о «конкатенировании» таблиц не имеет смысла в таблицах Lua. )

+0

gimf, вы были правы. Я неправильно интерпретировал использование списков в таблицах, чтобы думать, что их можно просто конкатенировать. Дальнейшие испытания привели меня к выводу, что то, что мне действительно нужно было, было слияние. Благодарим вас за помощь и терпение с новичком Lua. –

+1

@ Джон, мы все были новичками, когда-то ... из сложных языков, иногда удивительно, сколько власти скрывается в простоте Lua. Это может занять некоторое время, чтобы понять это. – RBerteig

4

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

Существуют особые случаи, когда конкатенация имеет смысл. Один из них относится к таблицам, содержащим простые массивы, что может быть естественным результатом функции, предназначенной для возврата списка результатов.

В этом случае, вы можете написать:

 
-- return a new array containing the concatenation of all of its 
-- parameters. Scaler parameters are included in place, and array 
-- parameters have their values shallow-copied to the final array. 
-- Note that userdata and function values are treated as scalar. 
function array_concat(...) 
    local t = {} 
    for n = 1,select("#",...) do 
     local arg = select(n,...) 
     if type(arg)=="table" then 
      for _,v in ipairs(arg) do 
       t[#t+1] = v 
      end 
     else 
      t[#t+1] = arg 
     end 
    end 
    return t 
end 

Это неполная копия, и не делает никаких попыток выяснить, если userdata или значение функции является контейнером или объект какого-то, что может понадобиться разным лечение.

Альтернативная реализация может изменить первый аргумент, а не создавать новую таблицу. Это позволит сэкономить затраты на копирование и сделать array_concat отличным от оператора .. по строкам.

Edit: Как было отмечено в комментарии по Joseph Kingry, я не смог правильно извлечь фактическое значение каждого аргумента из .... Я также не смог полностью вернуть объединенную таблицу из этой функции. Это то, что я получаю для кодирования в окне ответа, а не для тестирования кода вообще.

+0

+1 по понятию «естественный результат функции ... вернуть список результатов». Это вполне вероятно. – gimpf

+0

Я думаю, что в этой функции есть ошибка, я думаю, вам нужно другое 'select' там после' for', чтобы получить фактическое значение из '...'. http://lua-users.org/wiki/VarargTheSecondClassCitizen См. выпуск 8 –

+1

Yup. По-видимому, я не тестировал этот код перед публикацией, или этот дефект был бы очевиден. Более очевидным в ретроспективе является отсутствие «возврата t» до последнего «конца». – RBerteig

1

Вот реализация, которую я сделал аналогично RBerteig выше, но с использованием скрытого параметра arg, который доступен, когда функция получает переменное количество аргументов. Лично я считаю, что это более читаемо по сравнению с синтаксисом select.

function array_concat(...) 
    local t = {} 

    for i = 1, arg.n do 
     local array = arg[i] 
     if (type(array) == "table") then 
      for j = 1, #array do 
       t[#t+1] = array[j] 
      end 
     else 
      t[#t+1] = array 
     end 
    end 

    return t 
end 
5

Чтобы добавить две таблицы вместе это сделать

ii=0 
for i=#firsttable, #secondtable+#firsttable do 
    ii=ii+1 
    firsttable[i]=secondtable[ii] 
end 

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

  • i - начальный номер таблицы или списка.
  • #secondtable+#firsttable - это то, к чему нужно закончить.

Она начинается в конце первой таблицы вы хотите добавить, и заканчивается в конце второй таблицы в for петли, так она работает с любым размером таблицей или списком.

+0

Это неправильно. Вам нужно начинать с i = (# firsttable + 1), или вы будете пробивать последний элемент в первой таблице. В случае, если первая таблица пуста, вы даже попытаетесь получить доступ к первой таблице [0], но массивы индексируются начиная с 1 в lua. – scravy

24

Сложные ответы много?

вот моя реализация:

function TableConcat(t1,t2) 
    for i=1,#t2 do 
     t1[#t1+1] = t2[i] 
    end 
    return t1 
end 
+0

не будет итерации 'ipairs' с' table.insert' лучше (более читабельны и/или быстрее)? –

+0

ipairs является едва более дорогостоящим, чем обычно, причина не использовать его - это не гарантирует порядок элементов в таблице. причина не использовать вставку - это значительно дороже, чем стандартный индекс, установленный в таблице, потому что вставка вызовет подпрограмму, которая выталкивает значения в таблице обратно из индекса, на который она была вызвана, в то время как нет значений, предшествующих [#t +1], процедура по-прежнему вызывается, что вызывает проблему производительности, на компилированном языке нет никакой разницы, но с использованием интерпретируемого языка нам нужно быть осторожным, что все, что мы просим, ​​чтобы компьютер сделал для нас –

+4

От чего я знаете, 'ipairs' гарантирует, что порядок итерации будет' для i = 1' ... до первого t [i] == nil, no? Который для невырожденных случаев тот же, что и для i = 1, # t'. Re 'insert' vs indexing set, хотя вы правы - я измерял и разница в производительности 5-6x –

3

Простой способ сделать то, что вы хотите:

local t1 = {1, 2, 3, 4, 5} 
local t2 = {6, 7, 8, 9, 10} 

local t3 = {unpack(t1)} 
for I = 1,#t2 do 
    t3[#t1+I] = t2[I] 
end 
+0

Почему '{unpack (t1)}'?! все, что он делает, я делаю копию 't1', но вопрос подразумевает обновление на месте? –

+1

@ Насбанов. Он спросил, как конкатенировать. Когда вы объединяете строки, вы получаете новую строку. Я предположил, что он хотел чего-то подобного. – warspyking

+1

Хм, ты прав относительно слова «конкатенация» в названии. Но вопрос говорит о «добавлении», который является мутатором. Тем не менее '{unpack (tbl)}' - это аккуратный трюк для клонирования таблицы - с ограничениями (что-то вроде элементов 1M). –

2

И еще один способ:

for _,v in ipairs(t2) do 
    table.insert(t1, v) 
end 

Это кажется мне наиболее читаемый - он повторяет вторую таблицу и добавляет ее значения к 1-му, концу истории. Любопытно, как это ускоряется в скорости до явного индексации [] выше

1

Вот моя реализация, чтобы объединить набор таблиц с индексом чистого целого, FYI.

  1. определить функцию объединения двух таблиц, concat_2tables
  2. другой рекурсивную функцию concatenateTables: разделить список таблицы на unpack и вызвать concat_2tables конкатенировать table1 и restTableList

    t1 = {1, 2, 3} 
    t2 = {4, 5} 
    t3 = {6} 
    
    concat_2tables = function(table1, table2) 
        len = table.getn(table1) 
        for key, val in pairs(table2)do 
         table1[key+len] = val 
        end 
        return table1 
    end 
    
    concatenateTables = function(tableList) 
        if tableList==nil then 
         return nil 
        elseif table.getn(tableList) == 1 then 
         return tableList[1] 
        else 
         table1 = tableList[1] 
         restTableList = {unpack(tableList, 2)} 
         return concat_2tables(table1, concatenateTables(restTableList)) 
        end 
    end 
    
    tt = {t1, t2, t3} 
    t = concatenateTables(tt) 
    
Смежные вопросы