วิธีรับจำนวนรายการในตาราง Lua


132

ดูเหมือนคำถาม "ให้ฉันใช้ Google ให้คุณ" แต่ฉันไม่สามารถหาคำตอบได้ ตัว#ดำเนินการLua จะนับเฉพาะรายการที่มีคีย์จำนวนเต็มและทำเช่นนั้นtable.getn:

tbl = {}
tbl["test"] = 47
tbl[1] = 48
print(#tbl, table.getn(tbl))   -- prints "1     1"

count = 0
for _ in pairs(tbl) do count = count + 1 end
print(count)            -- prints "2"

ฉันจะรับจำนวนรายการทั้งหมดโดยไม่นับได้อย่างไร


3
@lhf: ฉันได้เขียน serializer ซึ่งจำทุกวัตถุที่เห็นและในครั้งต่อไปที่เห็นมันจะปล่อยการอ้างอิงจำนวนเต็มแทนที่จะเป็นวัตถุ วิธีธรรมชาติในการเขียนสิ่งนี้คือสิ่งdictionary[value] = #dictionary + 1ที่#แสดงถึงจำนวนของวัตถุทั้งหมด สิ่งที่ฉันสงสัยคือทำไมคุณไม่ต้องการสิ่งนี้: ในทุกกรณีการใช้งานที่มีเหตุผลสำหรับ # (ดูคำตอบโดย kaizer.se) จำนวนของวัตถุทั้งหมดจะเท่ากับสิ่งที่ # ส่งคืนแล้ว ดูเหมือนว่าการ # นับทุกอย่างเป็นการปรับปรุงอย่างเคร่งครัด แน่นอนว่าฉันเป็นมือใหม่ของ Lua และอาจจะพลาดประเด็นนี้ไป
Roman Starkov

32
@lhf: ไม่ใช่เรื่องดีที่คุณจะตั้งคำถามถึงความสามารถของโปรแกรมเมอร์โดยการถามว่าทำไมเขาถึงต้องทำอะไรบางอย่างที่ภาษาโปรแกรมที่สมเหตุสมผลทั้งหมดมีฟังก์ชันง่ายๆ
Timwi

5
@ Timwi: เป็นเรื่องไม่ดีที่คุณจะบอกผู้เขียนภาษา Lua คนหนึ่งว่า Lua ไม่ได้อยู่ในภาษาโปรแกรมที่ "สมเหตุสมผล" ;-) BTW ฉันไม่เคยต้องการข้อมูลนั้นเช่นกัน
Alexander Gladysh

5
ฉันไม่คิดว่าฉันเคยใช้ทุกคุณสมบัติของภาษาเดียว นั่นไม่ได้หมายความว่ามันไม่มีประโยชน์กับคนอื่น :)
Roman Starkov

7
@sylvanaar ในความคิดของฉันตัว#ดำเนินการนั้นไม่ถูกกำหนดไว้ สิ่งนี้สามารถแก้ไขได้ง่ายมาก: ประการแรกทำการ#กำหนดค่าและประการที่สองแนะนำตัวดำเนินการหรือฟังก์ชันใหม่เพื่อรับจำนวนยี้ห้อ จบเรื่อง ... ทำไมพวกเขาต้องดื้อขนาดนี้? :)
Roman Starkov

คำตอบ:


129

คุณมีวิธีการแก้ปัญหาในคำถาม - pairs(..)วิธีเดียวคือการย้ำตารางทั้งหมดที่มี

function tablelength(T)
  local count = 0
  for _ in pairs(T) do count = count + 1 end
  return count
end

นอกจากนี้โปรดสังเกตว่าคำจำกัดความของโอเปอเรเตอร์ "#" ซับซ้อนกว่านั้นเล็กน้อย ผมขอยกตัวอย่างโดยใช้ตารางนี้:

t = {1,2,3}
t[5] = 1
t[9] = 1

ตามคู่มือใด ๆ ของ 3, 5 และ 9 #tเป็นผลที่ถูกต้องสำหรับ วิธีเดียวที่ดีในการใช้คือกับอาร์เรย์ของส่วนที่ต่อเนื่องกันโดยไม่มีค่าศูนย์


42
ฉันยังคงสั่นสะท้านในความทรงจำเกี่ยวกับประสบการณ์ของฉันกับ Lua เมื่อฉันตระหนักว่าค่าตอบแทนของตัวดำเนินการพื้นฐานเช่น#นั้นไม่ได้ถูกกำหนด
Roman Starkov

5
โอ้มันน่าจะเป็นปัจจัยกำหนด มันเหมือนกับเวลาที่มาตรฐาน C ปล่อยให้บางสิ่งบางอย่างเป็นพฤติกรรมที่กำหนดไว้ในการนำไปใช้งาน เหตุผลที่เป็นเช่นนี้ก็คือผู้ปฏิบัติงานที่แตกต่างกันสามารถเลือกตัวเลือกการใช้งานที่แตกต่างกันได้
เปล่า

19
According to the manual, any of 3, 5 and 9 are valid results for #t. ตามคู่มือเรียก # ไม่ใช่ลำดับแบบไม่ได้กำหนด นั่นหมายความว่าผลลัพธ์ใด ๆ (-1, 3, 3.14, 5, 9) ถูกต้อง
cubuspl42

6
เกี่ยวกับผลลัพธ์ที่ถูกต้อง: u0b34a0f6ae ถูกต้องสำหรับ Lua 5.1 ในขณะที่ cubuspl42 ถูกต้องสำหรับ Lua 5.2 ไม่ว่าในกรณีใดสิ่งทั้งหมดก็บ้าไปแล้ว
Jeremy

9
ความจริงที่ว่า # บนลำดับที่ไม่ใช่ไม่ได้สร้างข้อยกเว้นเป็นเพียงหนึ่งในสิ่งที่ทำให้การใช้ lua เหมือนกับการตัดตัวเองให้รู้สึกดีขึ้น
boatcoder

21

คุณสามารถตั้งค่า meta-table เพื่อติดตามจำนวนรายการซึ่งอาจเร็วกว่าการวนซ้ำหากจำเป็นต้องใช้ข้อมูลนี้บ่อยๆ


มีวิธีที่สะดวกในการจัดการการลบรายการด้วยวิธีนี้หรือไม่?
u0b34a0f6ae

น่าเศร้าที่ดูเหมือนว่าฟังก์ชัน __newindex จะไม่เริ่มทำงานในการกำหนดศูนย์เว้นแต่ไม่มีดัชนีดังนั้นดูเหมือนว่าคุณจะต้องลบช่องทางผ่านฟังก์ชันพิเศษ
ergosys

1
คุณควรจัดเก็บข้อมูลไว้ในตารางแยกกัน (เช่นสามารถเข้าถึงได้ในรูปแบบ upvalue สำหรับ __index และ __newindex) จากนั้นทั้ง __index และ __newindex จะเริ่มทำงานสำหรับการเข้าถึงแต่ละตาราง คุณควรตรวจสอบว่าประสิทธิภาพเป็นที่ยอมรับหรือไม่
Alexander Gladysh

@ อเล็กซานเดอร์: อ่าใช่แล้วจุดสะดุดต่อไป: ถ้าคุณพร็อกซีตารางการทำซ้ำตามคู่ปกติจะไม่ทำงาน สิ่งนี้จะสามารถแก้ได้ใน Lua 5.2 ฉันได้ยินมา
u0b34a0f6ae

จะมี __pairs และ __ipairs metamethods ใน 5.2 ... ถ้าคุณต้องการทำใน 5.1 คุณจะต้องแทนที่คู่ () ฟังก์ชั่นของคุณเอง แต่นั่นอาจจะมากเกินไป :-)
Alexander Gladysh

3

มีวิธีหนึ่ง แต่อาจน่าผิดหวัง: ใช้ตัวแปรเพิ่มเติม (หรือหนึ่งในฟิลด์ของตาราง) เพื่อจัดเก็บจำนวนและเพิ่มทุกครั้งที่คุณแทรก

count = 0
tbl = {}

tbl["test"] = 47
count = count + 1

tbl[1] = 48
count = count + 1

print(count)   -- prints "2"

ไม่มีวิธีอื่นตัวดำเนินการ # จะทำงานบนตารางเหมือนอาร์เรย์ที่มีคีย์ต่อเนื่องกันเท่านั้น


3
สิ่งนี้สามารถทำได้โดยอัตโนมัติด้วยตารางพร็อกซีและวิธีการเปลี่ยนแปลงตามที่กล่าวไว้ในคำตอบของ
ergosys

ฉันได้รับความประทับใจจากความคิดเห็นว่าสิ่งที่ proxytable / metamethods ยังไม่สนับสนุนสถานการณ์นี้อย่างสมบูรณ์ดังนั้นฉันจะยอมรับว่านี่เป็นวิธีที่ดีที่สุดที่มีอยู่ในขณะนี้
Roman Starkov

การนับเป็นวิธีเดียวสำหรับตารางและการเพิ่มเส้นเมื่อสร้างตารางจะดีกว่าฟังก์ชันที่จะนับทุกครั้งที่คุณต้องการนับ คุณสามารถเพิ่มคีย์ในตอนท้ายโดยกำหนดค่าเป็นจำนวนนับ
Henrik Erlandsson

2

วิธีที่ง่ายที่สุดที่ฉันรู้ในการรับจำนวนรายการในตารางคือการใช้ '#' #tableName รับจำนวนรายการตราบเท่าที่มีหมายเลข:

tbl={
    [1]
    [2]
    [3]
    [4]
    [5]
}
print(#tbl)--prints the highest number in the table: 5

น่าเสียดายที่หากไม่ได้นับเลขก็จะใช้ไม่ได้


2

คุณสามารถใช้ไลบรารีเพนไลท์ มีฟังก์ชันsizeที่ให้ขนาดจริงของตาราง

มีการใช้งานฟังก์ชั่นมากมายที่เราอาจต้องการในขณะที่เขียนโปรแกรมและหายไปใน Lua

นี่คือตัวอย่างการใช้งาน

> tablex = require "pl.tablex"
> a = {}
> a[2] = 2
> a[3] = 3 
> a['blah'] = 24

> #a
0

> tablex.size(a)
3

1
local function CountedTable(x)
    assert(type(x) == 'table', 'bad parameter #1: must be table')

    local new_t = {}
    local mt = {}

    -- `all` will represent the number of both
    local all = 0
    for k, v in pairs(x) do
        all = all + 1
    end

    mt.__newindex = function(t, k, v)
        if v == nil then
            if rawget(x, k) ~= nil then
                all = all - 1
            end
        else
            if rawget(x, k) == nil then
                all = all + 1
            end
        end

        rawset(x, k, v)
    end

    mt.__index = function(t, k)
        if k == 'totalCount' then return all
        else return rawget(x, k) end
    end

    return setmetatable(new_t, mt)
end

local bar = CountedTable { x = 23, y = 43, z = 334, [true] = true }

assert(bar.totalCount == 4)
assert(bar.x == 23)
bar.x = nil
assert(bar.totalCount == 3)
bar.x = nil
assert(bar.totalCount == 3)
bar.x = 24
bar.x = 25
assert(bar.x == 25)
assert(bar.totalCount == 4)

1
เมื่อโพสต์คำตอบขอแนะนำให้โพสต์โค้ดจำนวนน้อยที่สุดที่จะตอบคำถามโดยตรงและอธิบายว่าโค้ดตอบคำถามอย่างไร ดูที่นี่ .
cst1992

__newindexเรียกเฉพาะเมื่อกำหนดคีย์ใหม่ดังนั้นจึงไม่มีโอกาสเรียก__newindexเมื่อเราตั้งค่าnilเป็นคีย์ที่มีอยู่
Frank AK

-1

ดูเหมือนว่าเมื่อเพิ่มองค์ประกอบของตารางโดยวิธีการแทรก getn จะกลับมาอย่างถูกต้อง มิฉะนั้นเราจะต้องนับองค์ประกอบทั้งหมด

mytable = {}
element1 = {version = 1.1}
element2 = {version = 1.2}
table.insert(mytable, element1)
table.insert(mytable, element2)
print(table.getn(mytable))

มันจะพิมพ์ 2 อย่างถูกต้อง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.