remove item from a list by specific index - lua

I have this table:
local ls = {
["foo"] = {1, 2, 3, 4, 5},
["bar"] = {5, 4, 3, 2, 1}
}
I want to remove "foo" from list.
I tried this:
table.remove(ls, "foo")
but returns a error: "Only numbers"
Okay, but I can't input a number. This list isn't static, in my code a lot of indexes will be inserted in this list.
The question is, is there other way to do this or other function that fit my problem?

table.remove only works for a sequence. In your code, the table ls isn't one.
To remove an entry from a table, just assign the value of specific key to nil:
ls.foo = nil

Related

Best way to saving completed progress in table?

So, i have empty table.
local data_tbl = {}
But i need save data when user complete current task.
Like:
-- (1, 2, 21) it's task id.
data_tbl['1'] = true
data_tbl['2'] = true
data_tbl['21'] = true
And in table "data_tbl" it's look like
data_tbl {
1 = true,
2 = true,
21 = true,
}
I wan't saving only completed task. Not all , because it's very heavy ?
But when i wanted remove this key , like 21 , i'ts get nothing effect.
table.remove(data_tbl, 21)
Task with 21 index not removed. Why ?
Maybe have other best way for all this ? (Saving complete tasks)
I don't want use table.Add() because it's added to last position. Like table.Add(data_tbl, {completed_id = 21})
And in table it's look like.
data_tbl {
1 = {completed_id = 21}
}
-- It's get me more table checks... and cycles , i don't want.
table.insert and table.remove are meant for sequences, but you're using the table as a map. If you have a key, say 21 and want to unset it, just do data_tbl[21] = nil
lua tables are hash tables, to insert data to table use mytable[name] = value or mytable.myname = value, to remove from table mytable[name] = nil or mytable.myname = nil.
To simulate arrays lua tables has helper functions in module table and some sort of optimizations, but id's must be numbers and begin with 1.
For mixed tables like mytable[1] = true; mytable[2] = true; mytable[3] = true; mytable[21] = true; mytable.name = 'values', #mytable evaluates to length of 3 as entries [21] and 'name' do not form the sequence.
table.remove and table.insert modifies 'array' shifting corresponding elements:
local mytable = {1, 2, 3, 4}
table.remove(mytable, 2)
print(table.concat(mytable, ',')) -- result is {1, 3, 4 }
table.insert(mytable, 2, 5)
print(table.concat(mytable, ',')) -- result is {1, 5, 3, 4 }
Numeric strings as keys will be not converted internally into numbers (like in javascript) and will not work with array like methods:
local mytable = {}
mytable[21] = 'value21'
mytable['21'] = 'string21'
-- table content: {[21] = 'value21', ['21'] = 'string21'}

In Rails, how do I figure out if an array of objects contains specific attributes matching given values?

I'm using Ruby on Rails 5.0.1 with Ruby 2.4. I have an array of objects, stored in the array, "results." Each object has a numeric attribute
numeric_attr
I would like to know, given my array, how I can tell if I have exactly one object with a numeric attribute value of "1" and incrementing by one. Order is not important. So, for instance, if I have an array of three objects,
[MyObject(numeric_attr = 2), MyObject(numeric_attr = 1), MyObject(numeric_attr = 3)]
I want to know if I have exactly one object with numeric_attr = 1, another object with numeric_attr = 2, and another with numeric_attr = 3. So the above satisfies the condition. The below example does not
[MyObject(numeric_attr = 4), MyObject(numeric_attr = 1), MyObject(numeric_attr = 3)]
because although there is an object with numeric_attr = 1, there is no object with numeric_attr = 2. It is possible thet the numeric_attr field is nil. How can I figure this out?
This one-liner should work:
results.map(&:numeric_attr).sort == (1..results.count).to_a
Explanation:
results
#=> [#<MyObject:... #attr=2>, #<MyObject:... #attr=3>, #<MyObject:... #attr=1>]
results.map(&:attr)
#=> [2, 3, 1]
results.map(&:attr).sort
#=> [1, 2, 3]
(1..results.length).to_a
#=> [1, 2, 3]
# therefore:
results.map(&:attr).sort == (1..results.count).to_a
#=> true
If there is a chance that numeric_attr is nil:
results.map(&:attr).compact.sort == (1..results.count).to_a
Of course, if there is even a single nil value, the result is guaranteed to be false.
If the sequence could start at any number, not just 1:
results.map(&:attr).sort == results.count.times.to_a.
map { |i| i + results.map(&:attr).sort.first }
This is not very efficient though, as it sorts the numbers twice.
If they always start at 1 #Máté's solution works, if they can start at any arbitrary number then you could:
count = 0
array_objects.sort_by(&:numeric_attr).each_cons(2) {|a,b| count+=1 if a.numeric_attr==b.numeric_attr-1 }
count+1==array_objects.count
Not as elegant but handles a lot more situations

Select from Tarantool by secondary index with sort by another field and limit/offset

I have some space top with fields:
-id,
-status,
-rating
I have two indexes for space top:
--primary
box.space.top:create_index('primary', { type = 'TREE', unique = true, parts = { 1, 'NUM' } })
--status
box.space.top:create_index('status', { type = 'TREE', unique = false, parts = { 2, 'NUM' } })
I can select by id or status
--select by id
space.top.index.primary:select(someId)
--select by status with limit/offset
space.top.index.status:select({someStatus}, {iterator = box.index.EQ, offset = 0, limit = 20})
Sometimes i need select by status with ordering by rating.
What is the best way? Create another index with parts status, rating and make some tricky query if it`s possible? Or continue select by status and make sort by rating in Lua procedure?
Thanks!
UPD:
Thanks, Kostya!
I modified index status like this:
box.space.top:create_index('status_rating', { type = 'TREE', unique = false, parts = { 2, 'NUM', 3 'NUM' } })
And now i can query:
local active_status = 1
local limit = 20
local offset = 0
box.space.top.index.status_rating:select({active_status}, {iterator = box.index.LE, offset=offset, limit=limit})
Great!
Doesn't make sense to create the third index, if you need to order by rating, just include it into the second index as the second part, and use GE/GT iterator, the data will come out ordered. This is an in-memory database, adding more parts to an index doesn't use up more memory, only slows down insertion a bit.
Call with GE/LE iterator and partial index may work not as expected than there is no matching tuples or limit is too high.
Suppose, we have following tuples (status, rating):
{ 1, 1 }
{ 3, 1 }
{ 3, 2 }
Than call
box.space.top.index.status_rating:select({2}, {iterator = box.index.GE, limit=1})
will return tuple {3, 1} as it greater than {2}
And call
box.space.top.index.status_rating:select({1}, {iterator = box.index.GE, limit=2})
will return two tuples {1, 1}, {3, 1}
In both case tuple {3, 1} may be not expected

Lua: Adding multiple rows to tables

Ok, so I'm looking to quickly generate a rather large table. Something that would look like this:
table{
{1, 1, 1, 1},
{1, 1, 1, 1},
{1, 1, 1, 1},
}
Only the table would contain far more rows, and far more values in those rows. I know using table.insert() I can easily add however many I need to a single row, but is there anyway I can also add whole new rows without typing it all out?
Use a for loop.
t = { }
for i = 1,100 do
table.insert(t, i) -- insert numbers from 1 to 100 into t
end
2D arrays are also very simple
t = { }
for row = 1,20 do
table.insert(t, { }) -- insert new row
for column = 1,20 do
table.insert(t[row], "your value here")
end
end
You could remember current row as in local current_row = t[row], but don't try these things to improve performance until you profile! Use them merely for readability, if you think it clearer expresses the purpose.
Also note that (and it's especially funky in 5.1 and newer with the #) you can just directly assing values to nonexisting indices, and they will be added.
You don't need to use table.insert:
t = {}
for row = 1,20 do
t[row] = {}
for column = 1,20 do
t[row][column]= "your value here"
end
end

Nested tables and numerical keys in Lua

I'm not sure if this is possible due to the numerical indices, but hopefully someone can point me in the right direction.
Given the table of:
t = { 13, 200, 12, 15, 23 }
how can I nest a table using the numbers?
t["200"] = {"stuff", "more stuff", "even more stuff"}
doesn't seem to work, as it'll create a position 200 and fill in the empty cells with null. I'd add a letter as a suffix/prefix, but the problem comes trying to sort the table numerically. Is this even possible, or am I stuck with a different method? Thanks!
Slight edit due to a realisation:
t["200"] = {"stuff", "more stuff", "even more stuff"}
actually creates a key of "200", whereas:
t[200] = {"stuff", "more stuff", "even more stuff"}
creates the index 200 with everything else null.
First, DeadMG is correct; you used a string rather than a numerical index. However, even if you did use a number index, it wouldn't help.
If you do this:
someTable = {"value1", "value2", {"value3a", "value3b"}};
someTable[50] = {"value50a", "value50b"};
The length of the table, #someTable, will still be 3. Why? Because Lua defines arrays in a table based on contiguous elements. Remember: you can access any element of any table; they are all conceptually filled with nil until you give them an actual value.
Lua defines length for a table as the number of values in a table if you start counting from numerical index 1 until you reach the first nil value. Since someTable[4] is nil, the length is 3.
If you want to insert a new element at the end of an array table, then you can do this:
someTable[#someTable + 1] = "newValue";
The value can itself be a table:
someTable[#someTable + 1] = {"newValuea", "newValueb"};
If you're just asking how to access a nested table, that's simple, and it has nothing to do with the keys you use.
There is nothing special about nested tables. Tables are values, and table entries can be any value, including other tables.
If you have a table, and want to walk the array entries in it, you use this:
local aTable = {"first", "second", "third", ...}
for i, value in ipairs(aTable) do
--`value` contains the entries in the table.
end
A nested table is no different; it is simply a matter of getting the table.
local nestedTable = { "first", "second", "third", ...}
nestedTable[#nestedTable + 1] = {"newFirst", "newSecond", ...}
local aTable = nestedTable[#nestedTable];
for i, value in ipairs(aTable) do
--`value` contains the entries in the table.
end
Or you could just do ipairs(nestedTable[#nestedTable]). Note that the particular key used here (an integer value) is entirely unimportant. That key could have been a string, a floating-point number, another table, some user-data, etc. It doesn't matter.
Note also that we use ipairs because we only want to iterate over the array members of the table. The length of the array is defined above. If we wanted to loop over every member of the table, we would use pairs instead of ipairs. Of course, pairs does an unordered search, so it is not guaranteed to be in array order.
If you want to recursively find every element in a nested table, you can do this:
local function RecursiveSearch(aTable)
for key, value in pairs(aTable) do --unordered search
if(type(value) == "table") then
RecursiveSearch(value)
else
--Do something with this.
end
end
end
Note that the above can do an infinite loop, since it is possible for a table to have circular references:
local tableA = {}
local tableB = {tableA}
local tableA[1] = tableB
RecursiveSearch(tableA) --Infinite loop.
Perhaps it helps to view your assignment like this:
t = { [1] = 13, [2] = 200, [3] = 12, [4] = 15, [5] = 23 }
To change what is currently 200 (namely t[2]), you do:
t[2] = {"stuff", "more stuff", "even more stuff"}
Edit: that results in your table looking like this:
t = { [1] = 13, [2] = {"stuff", "more stuff", "even more stuff"}, [3] = 12, [4] = 15, [5] = 23 }
-- or, equivalent::
t = { 13, {"stuff", "more stuff", "even more stuff"}, 12, 15, 23 }
The trouble is your use of "". Your table t contains a bunch of numbers, and you're entering a string as the key. You want to iterate over the table and do... something that you didn't particularly well define. However, you can't add to a table whilst iterating over it, so you might have to do some funny stuff.
t = { 13, 200, 12, 15, 23 }
newt = {};
for key, value in pairs(t) {
newt[value] = { };
}
This will create a table entry in newt, where the key is a value in the table t, for all values in t.

Resources