سؤال

هذا هو سؤال روبي 1.8:

كلنا نعرف كيف نستخدم Array#uniq :

[1,2,3,1].uniq #=> [1,2,3]

ومع ذلك ، أتساءل عما إذا كان بإمكاننا قرد تصحيحها بطريقة للعمل مع كائنات معقدة. السلوك الحالي مثل هذا:

[{"three"=>"3"}, {"three"=>"4"}, {"three"=>"3"}].uniq 
#=> [{"three"=>"3"}, {"three"=>"4"}, {"three"=>"3"}]

المطلوب هو:

[{"three"=>"3"}, {"three"=>"4"}, {"three"=>"3"}].uniq 
#=> [{"three"=>"3"}, {"three"=>"4"}]
هل كانت مفيدة؟

المحلول

إنه يعمل بالفعل بالنسبة لي في 1.8.7.

1:~$ ruby -v
ruby 1.8.7 (2008-08-11 patchlevel 72) [i486-linux]
1:~$ irb -v
irb 0.9.5(05/04/13)
1:~$ irb
>> [{"three"=>"3"}, {"three"=>"4"}, {"three"=>"3"}].uniq 
=> [{"three"=>"3"}, {"three"=>"4"}]

نصائح أخرى

لجعل Array#Uniq يعمل من أجل أي كائن يجب عليك تجاوز طريقتين: hash و eql؟

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

مثال-المستخدم فريد من نوعه عندما يكون عنوان بريده الإلكتروني فريدًا:

class User
  attr_accessor :name,:email

  def hash
    @email.hash
  end

  def eql?(o)
    @email == o.email
  end
end

>> [User.new('Erin Smith','roo@example.com'),User.new('E. Smith','roo@example.com')].uniq 
=> [#<User:0x1015a97e8 @name="Erin Smith", @email="maynurd@example.com"]

المشكلة هي Hash#hash و Hash#eql? كلاهما يعطي نتائج وهمية في Ruby 1.8.6. هذه واحدة من بقع Monkey النادرة جدًا التي كنت على استعداد لأداءها ، لأن هذا الخطأ يكسر بشكل خطير الكثير من التعليمات البرمجية - ولا سيما وظائف المذكرات. فقط كن حذرًا مع بقع القرد التي لا تتغلب عليها السلوك غير المنكسر.

لذا:

class Hash
  if {}.hash != {}.hash
    def hash
      # code goes here
    end
  end
  if !{}.eql?({})
    def eql?(other)
      # code goes here
    end
  end
end

ولكن إذا كنت تفعل شيئًا حيث يمكنك التحكم في بيئة النشر ، فما عليك سوى رفع خطأ إذا بدأ التطبيق بـ 1.8.6.

وماذا عن هذا؟

h={}
[{"three"=>"3"}, {"three"=>"4"}, {"three"=>"3"}].select {|e| need=!h.key?(e) ; h[e]=1 ; need} 
#=> [{"three"=>"3"}, {"three"=>"4"}]

لقد واجهت هذا بنفسي عدة مرات. تجزئة المساواة في Ruby 1.8.6 مكسورة:

require 'test/unit'

class TestHashEquality < Test::Unit::TestCase
  def test_that_an_empty_Hash_is_equal_to_another_empty_Hash
    assert({}.eql?({}), 'Empty Hashes should be eql.')
  end
end

يمر في Ruby 1.9 و Ruby 1.8.7 ، فشل في Ruby 1.8.6.

1.8.7 :039 > [{"three"=>"3"}, {"three"=>"4"}, {"three"=>"3"}].uniq {|x|x.values} 
=> [{"three"=>"3"}, {"three"=>"4"}] 
1.8.7 :040 > [{"three"=>"3"}, {"three"=>"4"}, {"three"=>"3"}].uniq {|x|x.keys}
=> [{"three"=>"3"}] 

ماذا عن شيء من هذا القبيل؟ فقط uniq_by قيمة التجزئة أو مفتاح التجزئة عبر الكتلة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top