From ccf7696fa70c6719c56acdfa5deab74c05e9058c Mon Sep 17 00:00:00 2001
From: Ary Borenszweig <aborenszweig@manas.com.ar>
Date: Sun, 2 Nov 2014 10:05:44 -0300
Subject: [PATCH] Better Array#uniq! implementation

---
 src/array.cr | 44 ++++++++++++++++++++++++++++++++------------
 1 file changed, 32 insertions(+), 12 deletions(-)

diff --git a/src/array.cr b/src/array.cr
index 88171eb0eb..74eefad3fb 100644
--- a/src/array.cr
+++ b/src/array.cr
@@ -34,7 +34,7 @@ class Array(T)
   end
 
   def &(other : Array(U))
-    hash = other.each_with_object(Hash(T, Bool).new) { |o, h| h[o] = true }
+    hash = other.to_lookup_hash
     ary = Array(T).new(Math.min(length, other.length))
     i = 0
     each do |obj|
@@ -77,7 +77,7 @@ class Array(T)
 
   def -(other : Array(U))
     ary = Array(T).new(length - other.length)
-    hash = other.each_with_object(Hash(T, Bool).new) { |o, h| h[o] = true }
+    hash = other.to_lookup_hash
     each do |obj|
       ary << obj unless hash.has_key?(obj)
     end
@@ -264,7 +264,7 @@ class Array(T)
     end
     true
   end
-  
+
   def fill
     each_index { |i| @buffer[i] = yield i }
 
@@ -628,16 +628,23 @@ class Array(T)
   end
 
   def uniq!(&block : T -> U)
-    uniq_elements = Set(U).new
-    delete_if do |elem|
-      key = yield elem
-      if uniq_elements.includes? key
-        true
-      else
-        uniq_elements << key
-        false
-      end
+    if length <= 1
+      return self
+    end
+
+    hash = to_lookup_hash { |elem| yield elem }
+    if length == hash.length
+      return self
+    end
+
+    @length = hash.length
+
+    ptr = @buffer
+    hash.each do |k, v|
+      ptr.value = v
+      ptr += 1
     end
+
     self
   end
 
@@ -722,4 +729,17 @@ class Array(T)
     end
     index
   end
+
+  protected def to_lookup_hash
+    to_lookup_hash { |elem| elem }
+  end
+
+  protected def to_lookup_hash(&block : T -> U)
+    each_with_object(Hash(U, T).new) do |o, h|
+      key = yield o
+      unless h.has_key?(key)
+        h[key] = o
+      end
+    end
+  end
 end
-- 
GitLab