وضع روبي التجزئة .الافتراضي إلى قائمة [مكررة]

StackOverflow https://stackoverflow.com/questions/190740

  •  08-07-2019
  •  | 
  •  

سؤال

كنت أعتقد أنني فهمت ما الأسلوب الافتراضي لا تجزئة...

تعطي القيمة الافتراضية لمفتاح إذا لم تكن موجودة:

irb(main):001:0> a = {}
=> {}
irb(main):002:0> a.default = 4
=> 4
irb(main):003:0> a[8]
=> 4
irb(main):004:0> a[9] += 1
=> 5
irb(main):005:0> a
=> {9=>5}

كل شيء جيد.

ولكن إذا كنت تعيين الافتراضي إلى قائمة فارغة أو فارغة التجزئة ، أنا لا أفهم سلوك في كل....

irb(main):001:0> a = {}
=> {}
irb(main):002:0> a.default = []
=> []
irb(main):003:0> a[8] << 9
=> [9]                          # great!
irb(main):004:0> a
=> {}                           # ?! would have expected {8=>[9]}
irb(main):005:0> a[8]
=> [9]                          # awesome!
irb(main):006:0> a[9]
=> [9]                          # unawesome! shouldn't this be [] ??

كنت أتمنى/أتوقع نفس السلوك كما لو كنت قد استخدمت ||= مشغل...

irb(main):001:0> a = {}
=> {}
irb(main):002:0> a[8] ||= []
=> []
irb(main):003:0> a[8] << 9
=> [9]
irb(main):004:0> a
=> {8=>[9]}
irb(main):005:0> a[9]
=> nil

يمكن لأي شخص أن يشرح ما الذي يجري ؟

هل كانت مفيدة؟

المحلول

Hash.default يستخدم لتعيين القيمة الافتراضية عاد عند الاستعلام عن مفتاح غير موجود.لم يتم إنشاء إدخال في المجموعة لك، لمجرد الاستعلام عنه.

وكذلك القيمة التي قمت بتعيينها default to هو مثيل لكائن (مصفوفة في حالتك)، لذلك عندما يتم إرجاعه، يمكن معالجته.

a = {}
a.default = []     # set default to a new empty Array
a[8] << 9          # a[8] doesn't exist, so the Array instance is returned, and 9 appended to it
a.default          # => [9]
a[9]               # a[9] doesn't exist, so default is returned

نصائح أخرى

وهذا لفظ مفيد جداً:

(myhash[key] ||= []) << value

يمكن حتى أن تكون متداخلة:

((myhash[key1] ||= {})[key2] ||= []) << value

والطريقة الأخرى هي القيام بما يلي:

myhash = Hash.new {|hash,key| hash[key] = []}

ولكن هذا له آثار جانبية كبيرة يسأل حول المفتاح سوف يقوم بإنشائه، والذي يعرض has_key؟عديمة الفائدة إلى حد ما، لذلك أتجنب هذه الطريقة.

أعتقد أن هذا هو السلوك الذي تبحث عنه.سيؤدي هذا تلقائيًا إلى تهيئة أي مفاتيح جديدة في التجزئة إلى مصفوفة:

irb(main):001:0> h = Hash.new{|h, k| h[k] = []}
=> {}
irb(main):002:0> h[1] << "ABC"
=> ["ABC"]
irb(main):003:0> h[3]
=> []
irb(main):004:0> h
=> {1=>["ABC"], 3=>[]}

جلين ماكدونالدز يقول:

"الطريقة الأخرى هي أن تفعل:

myhash = التجزئة.جديد {|التجزئة الرئيسية| تجزئة[الرئيسية] = []}

ولكن هذا له كبير أثر جانبي أن يسأل عن مفتاح خلق ذلك ، مما يجعل has_key?غير مجدية إلى حد ما ، لذا تجنب هذا الأسلوب."

التي في الواقع لا يبدو أن يكون صحيحا.

irb(main):004:0> a = Hash.new {|hash,key| hash[key] = []}
=> {}
irb(main):005:0> a.has_key?(:key)
=> false
irb(main):006:0> a[:key]
=> []
irb(main):007:0> a.has_key?(:key)
=> true

الوصول إلى المفتاح خلق كما كنت أتوقع.مجرد سؤال has_key?لا.

إذا كنت تريد حقًا الحصول على تجزئة عميقة لا نهاية لها:

endless = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
endless["deep"]["in"]["here"] = "hello"

بالطبع، كما أشار جلين أعلاه، إذا قمت بذلك، فلن يظهر مفتاح has_key؟يفقد معناه لأنه سيعود دائمًا صحيحًا.شكرا لjbarnette لهذا واحد.

irb(main):002:0> a.default = []
=> []
irb(main):003:0> a[8] << 9
=> [9]                          # great!

بهذا البيان، قمت بتعديل الإعداد الافتراضي؛لم تقم بإنشاء مصفوفة جديدة وإضافة "9".في هذه المرحلة، يكون الأمر مماثلاً لو كنت قد فعلت ذلك بدلاً من ذلك:

irb(main):002:0> a.default = [9]
=> [9]

لذلك ليس من المستغرب أن تحصل الآن على هذا:

irb(main):006:0> a[9]
=> [9]                          # unawesome! shouldn't this be [] ??

علاوة على ذلك، أضاف '<<' الرقم '9' إلى المصفوفة؛ولم يضيفه إلى التجزئة، وهو ما يفسر ذلك:

irb(main):004:0> a
=> {}                           # ?! would have expected {8=>[9]}

بدلاً من استخدام .default، فإن ما تريد القيام به على الأرجح في برنامجك هو شيء من هذا القبيل:

# Time to add a new entry to the hash table; this might be 
# the first entry for this key..
myhash[key] ||= []
myhash[key] << value

لست متأكدًا مما إذا كان هذا هو ما تريده، ولكن يمكنك القيام بذلك لإرجاع مصفوفة فارغة دائمًا عند الاستعلام عن مفتاح التجزئة المفقود.

h = Hash.new { [] }
h[:missing]
   => []

#But, you should never modify the empty array because it isn't stored anywhere
#A new, empty array is returned every time
h[:missing] << 'entry'
h[:missing]
   => []
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top