2012-02-08 8 views
5

मैं एक लुआ टेबल स्टोर करना चाहता हूं जहां चाबियां अन्य लुआ टेबल हैं। मुझे पता है कि यह संभव है लेकिन मैं उन तालिकाओं की प्रतियों का उपयोग कर तालिका में दिखने में सक्षम होना चाहता हूं। विशेष रूप से, मैं ऐसा करने में सक्षम होना चाहता हूँ:लुआ: एक टेबल में कैसे दिखें जहां चाबियाँ टेबल (या ऑब्जेक्ट्स)

t = {} 
key = { a = "a" } 
t[key] = 4 
key2 = { a = "a" } 

और फिर मैं को देखने के लिए सक्षम होना चाहते हैं:

t[key2] 

और 4.

मुझे पता है कि मैं key बदल सकते हैं मिलता है एक स्ट्रिंग में और इसे तालिका t में डाल दें। मैंने एक कस्टम हैश फ़ंक्शन लिखने या घोंसले की मेजबानी करके ऐसा करने के बारे में भी सोचा है। क्या इस प्रकार की कार्यक्षमता पाने के लिए मेरे पास कोई अच्छा तरीका है? मेरे पास अन्य विकल्प क्या हैं?

उत्तर

6

लुआ में, अलग से बनाई गई दो तालिकाओं "अलग" माना जाता है। लेकिन यदि आप एक बार एक टेबल बनाते हैं, तो आप इसे किसी भी चर के लिए असाइन कर सकते हैं, और जब आप उनकी तुलना करते हैं, तो लुआ आपको बताएगा कि वे बराबर हैं। दूसरे शब्दों में:

t = {} 
key = { a = "a" } 
t[key] = 4 
key2 = key 
... 
t[key2] -- returns 4 

तो, यह वही करने का सरल, साफ तरीका है जो आप चाहते हैं।कहीं भी key स्टोर करें, ताकि आप इसे उपयोग करके 4 वापस पुनर्प्राप्त कर सकें। यह भी बहुत तेज़ है।

यदि आप वास्तव में ऐसा नहीं करना चाहते हैं ... अच्छा, एक तरीका है। लेकिन यह दयालु अक्षम और बदसूरत है।

पहला भाग एक समारोह बना रहा है जो दो अलग-अलग तालिकाओं की तुलना करता है। यदि दो टेबल "समकक्ष" हैं, और यदि वे नहीं हैं तो यह सच होना चाहिए। आइए इसे बराबर कॉल करें। यह इस तरह काम करना चाहिए:

equivalent({a=1},{a=1})   -- true 
equivalent({a=1,b=2}, {a=1})  -- false 
equivalent({a={b=1}}, {a={b=2}}) -- false 

कार्य तालिकाओं कि टेबल खुद को शामिल संभाल करने पुनरावर्ती होना चाहिए,। यदि किसी तालिका में "एक दूसरे" शामिल है, तो इसमें भी बेवकूफ नहीं होना चाहिए, लेकिन इसमें अधिक तत्व हैं। मैं इस कार्यान्वयन के साथ बाहर आया; शायद वहां बेहतर लोग हैं।

local function equivalent(a,b) 
    if type(a) ~= 'table' then return a == b end 

    local counta, countb = 0, 0 

    for k,va in pairs(a) do 
    if not equivalent(va, b[k]) then return false end 
    counta = counta + 1 
    end 

    for _,_ in pairs(b) do countb = countb + 1 end 

    return counta == countb 
end 

मैं यहां उस समारोह को समझाने वाला नहीं हूं। मुझे उम्मीद है कि यह पर्याप्त है कि यह क्या करता है।

पहेली के दूसरे भाग में tequivalent फ़ंक्शन की तुलना करते समय फ़ंक्शन की तुलना करने पर शामिल है। यह सावधानीपूर्वक मेटाटेबल मैनिपुलेशन, और एक अतिरिक्त "भंडारण" तालिका के साथ किया जा सकता है।

हम मूल रूप से t को एक impostor में बदलते हैं। जब हमारा कोड एक कुंजी के तहत एक मूल्य को स्टोर करने के लिए कहता है, तो यह इसे स्वयं में सहेजता नहीं है; इसके बजाय यह अतिरिक्त तालिका में देता है (हम उस store पर कॉल करेंगे)। जब कोड t किसी मान के लिए पूछता है, तो यह इसे store में खोजता है, लेकिन इसे पाने के लिए equivalent फ़ंक्शन का उपयोग करता है।

local function equivalent(a,b) 
... -- same code as before 
end 

local store = {} -- this is the table that stores the values 

t = setmetatable({}, { 
    __newindex = store, 
    __index = function(tbl, key) 
    for k,v in pairs(store) do 
     if equivalent(k,key) then return v end 
    end 
    end 
}) 

प्रयोग उदाहरण:

इस कोड है

t[{a = 1}] = 4 

print(t[{a = 1}]) -- 4 
print(t[{a = 1, b = 2}]) -- nil 
0

मुझे यकीन नहीं है कि आप यह कर सकते हैं। आप मेटाटेबल का उपयोग करके तालिकाओं के लिए समानता को परिभाषित कर सकते हैं, लेकिन हैश फ़ंक्शन को परिभाषित करने का कोई तरीका नहीं है, और मुझे संदेह है कि अकेले समानता को परिभाषित करने के लिए आपको जो चाहिए वह करेगा। आप स्पष्ट रूप से समानता को परिभाषित कर सकते हैं, फिर pairs() का उपयोग करके तालिका में फिर से घुमाएं और स्वयं की चाबियों की तुलना करें, लेकिन यह O(n) में देखने के लिए क्या होगा।

2

लुआ में यह संभव नहीं है। यदि आप तालिकाओं के रूप में तालिकाओं का उपयोग करते हैं, तो कुंजी तालिका का विशिष्ट "उदाहरण" है। भले ही आप एक ही सामग्री के साथ एक अलग तालिका बनाते हैं, उदाहरण अलग है, इसलिए यह एक अलग कुंजी है।

यदि आप ऐसा कुछ करना चाहते हैं, तो आप एक प्रकार का हैश फ़ंक्शन बना सकते हैं, जो कि एक कुंजी के रूप में सेवा करने के लिए तालिका को घुमाता है (शायद आवश्यक होने पर भी पुनरावर्ती) और तालिका सामग्री का स्ट्रिंग प्रस्तुति तैयार करता है। इसे मानव-पठनीय होने की आवश्यकता नहीं है, जब तक कि यह अलग-अलग सामग्री के लिए अलग हो और समान सामग्री वाले तालिकाओं के बराबर हो। तालिका को पार करने के लिए pairs() का उपयोग करने के अलावा, आपको एक तालिका में चाबियां डालने की आवश्यकता होगी और उन्हें table.sort() का उपयोग करके सॉर्ट करना होगा, क्योंकि pairs() उन्हें मनमाने ढंग से क्रम में लौटाता है, और आप "बराबर" तालिकाओं के लिए एक ही स्ट्रिंग चाहते हैं।

एक बार जब आप इस तरह के स्ट्रिंग का निर्माण किया है, तो आप इसे एक प्रमुख के रूप में उपयोग कर सकते हैं:

function hash(t) ... end 
t = {} 
key1 = { a = "a", b = "b" } 
t[hash(key1)] = 4 
key2 = { a = "a", b = "b" } 
print(t[hash(key2)]) -- should print "4" if the hash function works correctly 

मेरी राय में, यह सब अनुक्रमण के सरल कार्य के लिए बहुत ही जटिल है, और आप को फिर से लगता है कि कर सकते हैं टेबल की प्रतियों का उपयोग कर अनुक्रमण के लिए आपकी इच्छा। आप ऐसी कार्यक्षमता क्यों चाहेंगे?

अद्यतन

आप केवल वाक्यांशों के साथ काम करने की जरूरत है, तो मुझे लगता है कि उन्हें इस तरह के श्रृंखलाबद्ध सामान्य हैश फंक्शन बनाने की तुलना में आसान है। यदि आपको वाक्यांशों के अनुक्रमों के लिए इसकी आवश्यकता है, तो आपको वास्तव में तालिकाओं के माध्यम से पुनरावृत्ति करने की आवश्यकता नहीं होगी और चाबियाँ क्रमबद्ध करने की आवश्यकता नहीं होगी, केवल प्रत्येक वाक्यांश से मुख्य जानकारी एकत्र करें। तुम अब भी एक सहायक समारोह है, जो आप के लिए एक उपयुक्त कुंजी बना सकते हैं का उपयोग करने की आवश्यकता होगी:

function pkey(...) 
    local n, args = select('#', ...), { ... } 
    for i=1,n do args[i] = args[i].value end -- extract your info here 
    return table.concat(args, ' ') -- space or other separator, such as ':'   
end 
tab[pkey(phrase1, phrase2, phrase3)] = "value" 
+0

धन्यवाद। कारण मैं चाहता था कि यह एक एनएलपी कार्य के लिए था। मैं वाक्यांशों को निकालता हूं जिन्हें मैं लुआ टेबल (प्रत्येक वाक्यांश को वाक्यांश के रूप में संग्रहीत करता हूं जो तालिका.इनर्ट का उपयोग कर इंडेक्स में मैप किया जाता है) और मैं वाक्यांशों की आवृत्ति गिनना चाहता हूं। मुझे पता है कि जो कुछ मैं चाहता हूं उसे करने के अन्य तरीके हैं (उदाहरण के लिए वाक्यांश को संयोजित करें और उस कुंजी को एक कुंजी के रूप में संयोजित स्ट्रिंग का उपयोग करें) लेकिन इसके लिए अतिरिक्त कार्यान्वयन चरणों की आवश्यकता होगी और यह काफी साफ नहीं होगा। मुझे पूरा यकीन है कि आप जावा में जो चाहते हैं वह कर सकते हैं और लुआ के लिए नया होने के नाते, मैं यह देखने की कोशिश कर रहा हूं कि कोई एनालॉग – akobre01

+0

ऐसा हैश फ़ंक्शन लिखना मुश्किल है क्योंकि ऑब्जेक्ट्स को ट्रैक करने का ऑर्डर इस बात पर निर्भर करता है कि कैसे यह बनाया गया था और उसी प्रविष्टियों के साथ तालिकाओं में अलग-अलग ट्रैवर्सल हो सकते हैं। – lhf

+0

यही कारण है कि मैंने एक टेबल में चाबियाँ एकत्र करने और लगातार कुंजी ऑर्डर सुनिश्चित करने के लिए इसे सॉर्ट करने के बारे में कहा। –

0

मैं भाषा संसाधन के बारे में बहुत पता नहीं है, और लक्ष्य के बारे में आप अपने कार्यक्रम के साथ तक पहुँचने के लिए चाहते हैं, लेकिन इस तरह टोकन एकत्र करने के बारे में क्या: एक नेस्टेड टेबल संरचना का उपयोग करें, जिसमें इंडेक्स टेबल स्टोर केवल प्रथम वाक्यांश टोकन द्वारा अनुक्रमित टेबल है, फिर प्रत्येक उप-सारणी में दूसरे वाक्यांश टोकन ... आदि द्वारा अनुक्रमित मान होता है ... जब तक आप एक वाक्यांश अंतिम टोकन तक नहीं पहुंच जाते , वह घटना के अनुरूप एक संख्या मूल्य सूचकांक होगा वाक्यांश की सीई।

  • मैं केले की तरह:

    शायद यह अगर आप दो निम्नलिखित वाक्यांश एक उदाहरण के साथ और अधिक स्पष्ट हो जाएगा।

  • मुझे गर्म लड़की पसंद है।

आपका सूचकांक निम्नलिखित संरचना होगा:

index["I"] = { 
    ["like"] = { 
     ["banana"] = 1, 
     ["hot"] = { 
      ["chick"] = 1 
     } 
    }  
} 

कि जिस तरह से आप एक ही ट्रेवर्सल कदम के साथ frenquencies भरोसा कर सकते हैं, और एक ही समय आप का अनुक्रमण पर आवृत्तियां गिनती में, लेकिन जैसा कि मैंने पहले कहा, यह आपके लक्ष्य के आधार पर निर्भर करता है, और यह आपके सूचकांक के माध्यम से अवसरों को खोजने के लिए आपको वाक्यांश को दोबारा विभाजित करने का संकेत देगा।

+0

जो मैं वास्तव में देख रहा हूं वह यह है: यदि मेरे पास एक = {"मैं", "पसंद", "केले"} और बी = {"मैं", "पसंद", "केला"} है और मैं टी लिखता हूं [ ए] = "चिड़ियाघर", मुझे एक स्थिर समय योजना चाहिए जहां टी [बी] == "चिड़ियाघर"। – akobre01

+0

जैसा कि पहले कहा गया था कि ऐसा करना असंभव है, आपको तालिका मूल्य पर पुनरावृत्ति करके मैन्युअल तुलना किसी बिंदु पर करना होगा। – Faylixe

+0

लेकिन क्या होगा यदि "मुझे गर्म लड़की पसंद है" के अलावा "मुझे पसंद है" वाक्यांश भी है? वह अपना "= 1" कहां रखेगा? –

1

kikito का जवाब अच्छा है, लेकिन कुछ खामियां हैं:

  • आप t[{a=1}] = true दो बार प्रदर्शन करते हैं, store
  • एक बार मूल्य में संशोधन (हैश तालिका के जीवन भर के लिए लीक स्मृति) दो तालिकाओं में शामिल होंगे आप पहले से ही संग्रहीत कर चुके हैं यह काम नहीं करता है, न ही आप इसे हटा सकते हैं। इसे बदलने का प्रयास करने से परिणामस्वरूप पुनर्प्राप्ति आपके द्वारा उस कुंजी को असाइन किए गए किसी भी मूल्य को वापस कर देगी।
  • एक्सेस प्रदर्शन ओ (एन) (एन संग्रहीत प्रविष्टियों की संख्या है और यह मानते हुए कि तालिका से लुआ का मूल्य पुनर्प्राप्ति ओ (1) है; पहला बिंदु के साथ संयुक्त, इस हैश तालिका के प्रदर्शन उपयोग

(भी ध्यान रखें कि kikito के "बराबर" समारोह यदि कोई तालिका एक परिपत्र संदर्भ में है अनंत लूप उत्पन्न होगा।)

यदि आप के साथ नीचा होगा तालिका में किसी भी जानकारी को बदलने/हटाने की जरूरत नहीं है, तो किकिटो का जवाब पर्याप्त होगा जैसा कि यह खड़ा है। अन्यथा, metatable तो __newindex करें कि तालिका में पहले से ही नहीं है कि बनाता है परिवर्तित किया जाना चाहिए मौजूद हैं:

t = setmetatable({}, { 
    __newindex = function(tbl, key, value) 
     for k,v in pairs(store) do 
      if equivalent(k,key) then 
       tbl[k] = value 
       return 
      end 
     end 
     store[key] = value 
    end, 
    __index = function(tbl, key) 
     for k,v in pairs(store) do 
      if equivalent(k, key) then return v end 
     end 
    end 
}) 

आप का सुझाव दिया है के रूप में, एक पूरी तरह से अलग विकल्प एक कस्टम हैशिंग समारोह लिखने के लिए है।

local function HashTable(Hash, Equals) 
    --Hash is an optional function that takes in any key and returns a key that lua can use (string or number). If you return false/nil, it will be assumed that you don't know how to hash that value. 
    -- If Hash is not provided, table-keys should have a GetHash function or a .Hash field 
    --Equals is an optional function that takes two keys and specify whether they are equal or not. This will be used when the same hash is returned from two keys. 
    -- If Equals is not provided, items should have a Equals function; items are in this case assumed to not be equal if they are different types. 
    local items = {} --Dict<hash, Dict<key, value>> 
    local function GetHash(item) 
     return Hash and Hash(item) or type(item) == "table" and (item.GetHash and item:GetHash() or item.Hash) or item 
    end 
    local function GetEquals(item1, item2) 
     if Equals then return Equals(item1, item2) end 
     local t1, t2 = type(item1), type(item2) 
     if t1 ~= t2 then return false end 
     if t1 == "table" and item1.Equals then 
      return item1:Equals(item2) 
     elseif t2 == "table" and item2.Equals then 
      return item2:Equals(item1) 
     end 
     return false 
    end 
    return setmetatable({}, { 
     __newindex = function(_, key, value) 
      local hash = GetHash(key) 
      local dict = items[hash] 
      if not dict then 
       if value ~= nil then --Only generate a table if it will be non-empty after assignment 
        items[hash] = {[key] = value} 
       end 
       return 
      end 
      for k, v in pairs(dict) do 
       if GetEquals(key, k) then --Found the entry; update it 
        dict[k] = value 
        if value == nil then --check to see if dict is empty 
         if next(dict) == nil then 
          items[hash] = nil 
         end 
        end 
        return 
       end 
      end 
      --This is a unique entry 
      dict[key] = value 
     end, 
     __index = function(_, key) 
      local hash = GetHash(key) 
      local dict = items[hash] 
      if not dict then return nil end 
      for k, v in pairs(dict) do 
       if GetEquals(key, k) then 
        return v 
       end 
      end 
     end 
    }) 
end 

प्रयोग उदाहरण:

local h = HashTable(
    function(t) return t.a or 0 end, --Hash 
    function(t1, t2) return t1.a == t2.a end) --Equals 
h[{a=1}] = 1 
print(h[{a=1}]) -- 1 
h[{a=1}] = 2 
print(h[{a=1}]) -- 2 
print(h[{a=1,b=2}]) -- 2 because Hash/Equals only look at 'a' 

स्वाभाविक रूप से, आप बेहतर हैश/कार्यों के बराबर लाने के लिए चाहता हूँ यहाँ एक HashTable कि कि का उपयोग कर सकते है।

तब तक जब तक आपकी चाबियों की हैश शायद ही कभी टकरा जाए, इस वर्ग का यह प्रदर्शन ओ (1) होना चाहिए।

: प्रतिक्रिया के लिए (ध्यान दें मैं kikito के लिए एक टिप्पणी के रूप में इस उत्तर के ऊपरी आधे डाल चाहते हैं, लेकिन मैं इस समय प्रतिष्ठा ऐसा करने के लिए नहीं है।)

संबंधित मुद्दे