# Compare and delete element from an array

**URL:** <https://www.ruby-forum.com/t/compare-and-delete-element-from-an-array/183462>\
**Category:** Ruby\
**Created:** [February 15, 2010, 12:45am UTC](https://www.ruby-forum.com/t/compare-and-delete-element-from-an-array/183462 "2010-02-15T00:45:02Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![gregm](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/bc79bd/32.png) [@gregm](https://www.ruby-forum.com/u/gregm)\
**Post date:** [February 15, 2010, 12:45am UTC](https://www.ruby-forum.com/t/compare-and-delete-element-from-an-array/183462/1 "2010-02-15T00:45:02Z")

</div>

Hi,  
I try to compare an arroy of Tag and an array of string. I would like to  
remove from my array of Tag all element that are in the array of string.  
I,ve done the method below that should be working fine. When i look at  
the console result, the element are equals, so is should be deleted but  
it is not. I donc understand why??.. 😕

#Method in Student Class  
def remove\_tags(array\_of\_tags)  
if !array\_of\_tags.empty?  
array\_of\_tags.each do |tag|  
tags.delete\_if {  
|x| x.name == tag  
puts x.name + “-”+ x.name.length.to\_s  
puts tag + “-”+ tag.length.to\_s  
puts “-----”  
}  
end  
puts tags  
end  
end

## #result Completed in 95ms (View: 83, DB: 5) | 200 OK [[http://localhost/students/1/edit](http://localhost/students/1/edit)] moi-3 moi-3

## greg-4 moi-3

#Tag:0x10442cf98  
#Tag:0x10442ced0

Here we see that the first element should be deleted, but when i display  
the array, it has not…

---

<div class="post-metadata">

**Author:** ![gregm](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/bc79bd/32.png) [@gregm](https://www.ruby-forum.com/u/gregm)\
**Post date:** [February 15, 2010, 1:50am UTC](https://www.ruby-forum.com/t/compare-and-delete-element-from-an-array/183462/2 "2010-02-15T01:50:15Z")

</div>

On Feb 14, 2010, at 15:45 , Greg Ma wrote:

> …  
> tags.delete\_if {  
> |x| x.name == tag  
> puts x.name + “-”+ x.name.length.to\_s  
> puts tag + “-”+ tag.length.to\_s  
> puts “-----”  
> }  
> …

> Here we see that the first element should be deleted, but when i display  
> the array, it has not…

delete\_if evaluates the block to see if it should delete the element or  
not. you’re debugging with puts (a bad idea to begin with) and puts  
returns nil. So you’re never going to delete anything.

I’d also recommend using string interpolation:

> puts x.name + “-”+ x.name.length.to\_s

vs:

---

<div class="post-metadata">

**Author:** ![gregm](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/bc79bd/32.png) [@gregm](https://www.ruby-forum.com/u/gregm)\
**Post date:** [February 15, 2010, 1:51am UTC](https://www.ruby-forum.com/t/compare-and-delete-element-from-an-array/183462/3 "2010-02-15T01:51:25Z")

</div>

On Sun, Feb 14, 2010 at 4:45 PM, Greg Ma [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> ```
> puts tags
> 
> ```
> 
> end  
> end

Move the line:

x.name == tag

to the end of the block:

def remove\_tags(array\_of\_tags)  
if !array\_of\_tags.empty?  
array\_of\_tags.each do |tag|  
tags.delete\_if {|x|  
puts x.name + “-”+ x.name.length.to\_s  
puts tag + “-”+ tag.length.to\_s  
puts “-----”  
x.name == tag  
}  
end  
puts tags  
end  
end

The Array#delete\_if() method only removes array elements IF the block  
evaluates to true. With the “x.name == tag” test positioned at the  
beginning of the block, it is effectively ignored, since the last  
expression in the block will be the block’s return value. You were  
returning whatever the ‘puts “-----”’ method returns–nil in this  
case, which is considered “false” and so no elements would ever be  
deleted. By moving the “x.name == tag” expression to the bottom of  
the block, you will return a boolean result of the comparison.

Here’s another example of this behavior:  
irb(main):001:0\> [“one”, “two”, “three”, “four”, “five”].delete\_if{|x|  
x==“two”;puts x}  
one  
two  
three  
four  
five  
=\> [“one”, “two”, “three”, “four”, “five”]  
irb(main):002:0\> [“one”, “two”, “three”, “four”, “five”].delete\_if{|x|  
puts x;x==“two”}  
one  
two  
three  
four  
five  
=\> [“one”, “three”, “four”, “five”]

Note that the first version with a “puts” at the end of the delete\_if  
block failed to remove element “two”, but reordering the operation in  
the second version worked.

Aaron out.

---

<div class="post-metadata">

**Author:** ![gregm](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/bc79bd/32.png) [@gregm](https://www.ruby-forum.com/u/gregm)\
**Post date:** [February 15, 2010, 6:48am UTC](https://www.ruby-forum.com/t/compare-and-delete-element-from-an-array/183462/4 "2010-02-15T06:48:52Z")

</div>

> Note that the first version with a “puts” at the end of the delete\_if  
> block failed to remove element “two”, but reordering the operation in  
> the second version worked.

Even if i remove the puts, it still doesnt remove anything.

def remove\_tags(array\_of\_tags)  
if !array\_of\_tags.empty?  
array\_of\_tags.each do |tag|  
tags.delete\_if { |x| x.name == tag }  
end  
end  
end

---

<div class="post-metadata">

**Author:** ![gregm](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/bc79bd/32.png) [@gregm](https://www.ruby-forum.com/u/gregm)\
**Post date:** [February 15, 2010, 8:44am UTC](https://www.ruby-forum.com/t/compare-and-delete-element-from-an-array/183462/5 "2010-02-15T08:44:51Z")

</div>

Thanks for the explanation!  
I finally found my error. In fact the delete\_if was correcty working but  
the modification from the array wasnt reproduce on the database.  
What am i missing to do so?

Greg

---

<div class="post-metadata">

**Author:** ![gregm](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/bc79bd/32.png) [@gregm](https://www.ruby-forum.com/u/gregm)\
**Post date:** [February 15, 2010, 8:08am UTC](https://www.ruby-forum.com/t/compare-and-delete-element-from-an-array/183462/6 "2010-02-15T08:08:54Z")

</div>

On Sun, Feb 14, 2010 at 10:48 PM, Greg Ma [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> ```
> tags.delete_if { |x| x.name == tag }
> end
> 
> ```
> 
> end  
> end

You call the “delete\_if()” method on the “tags” variable–where is  
tags defined? You’ve fixed one bug (and it was indeed a bug). If your  
code isn’t working now, it likely has to do with the scope where tags  
is defined. In your original post you didn’t mention getting a  
NameError “undefined local variable or method `tags’” exception, so  
unless your code (or whatever code executes your code) rescues such an  
exception silently, I assume that “tags” IS in fact defined  
somehow/somewhere.

Since I don’t know how your “tags” array or Student class works, I  
contrived something that’s probably very, very different, but may give  
you an idea where to look in your own code for your bug:

### CODE STARTS

class Tag  
def initialize(name)  
@name = name  
end  
attr\_accessor :name

def to\_s  
“TAG(#{@name})”  
end  
end

class Student  
def initialize()  
@tag\_list = []  
end

## Add a single tag to the Student:

def add\_tags(array\_of\_tags)  
array\_of\_tags.each do |tag\_name|  
@tag\_list \<\< Tag.new(tag\_name)  
end  
end

## Remove multiple tags from the Student:

def remove\_tags(array\_of\_tags)  
array\_of\_tags.each do |tag\_name|  
@tag\_list.delete\_if { |x| x.name == tag\_name }  
end  
end

def to\_s  
“STUDENT(” + @tag\_list.map{ |tag| tag.to\_s }.join(“,”) + “)”  
end  
end

jane\_doe = Student.new  
jane\_doe.add\_tags([“intelligent”, “lazy”, “geek”, “irresponsible”,  
“nerd”, “smart”])

puts “Jane has these tags:”  
puts jane\_doe.to\_s

tags\_to\_remove = [“lazy”, “irresponsible”]

puts “Removing tags with these names:”  
puts " " + tags\_to\_remove.join(“,”)

## Remove the tags:

jane\_doe.remove\_tags(tags\_to\_remove)

puts “After removal, Jane has these tags:”  
puts jane\_doe.to\_s

### CODE ENDS

### SAMPLE OUTPUT:

Jane has these tags:  
STUDENT(TAG(intelligent),TAG(lazy),TAG(geek),TAG(irresponsible),TAG(nerd),TAG(smart))  
Removing tags with these names:  
lazy,irresponsible  
After removal, Jane has these tags:  
STUDENT(TAG(intelligent),TAG(geek),TAG(nerd),TAG(smart))

### OUTPUT ENDS

In the above contrived sample, notice that the Student#remove\_tags()  
method is a bit different than your method. That’s because I defined  
the equiv. of your “tags” variable as a Student class instance  
variable “@tag\_list” instead. Also I omitted the “if” statement “if  
!@tag\_list.empty?” (or “if !tags.empty?” in your code) because the  
each method will not execute the block at all if the array is empty to  
begin with–it’s redundant and not needed.

I hope this gives you an idea of where in your own code to look to debug  
it.

Aaron out.

---

<div class="post-metadata">

**Author:** ![gregm](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/bc79bd/32.png) [@gregm](https://www.ruby-forum.com/u/gregm)\
**Post date:** [February 15, 2010, 9:12am UTC](https://www.ruby-forum.com/t/compare-and-delete-element-from-an-array/183462/7 "2010-02-15T09:12:40Z")

</div>

On Mon, Feb 15, 2010 at 1:44 AM, Greg Ma [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Thanks for the explanation!  
> I finally found my error. In fact the delete\_if was correcty working but  
> the modification from the array wasnt reproduce on the database.  
> What am i missing to do so?
> 
> ## Greg
> 
> Posted via [http://www.ruby-forum.com/](http://www.ruby-forum.com/).

Sounds like a Rails/ActiveRecord question, you’ll probably have more  
luck on  
that mailing list  
[http://groups.google.com/group/rubyonrails-talk](http://groups.google.com/group/rubyonrails-talk)

But for a good place to start, I assume you have a  
has\_and\_belongs\_to\_many  
association, in which case the guides imply you can just use delete

> **[Active Record Associations — Ruby on Rails Guides](https://guides.rubyonrails.org/association_basics.html#has-and-belongs-to-many-association-reference)**
>
> Active Record AssociationsThis guide covers the association features of Active Record.After reading this guide, you will know: How to declare associations between Active Record models. How to understand the various types of Active Record...

4.4.1.4 collection.delete(object, â€¦)  
The collection.delete method removes one or more objects from the  
collection  
by deleting records in the join table. This does not destroy the  
objects.  
@part.assemblies.delete(@assembly1)

---

<div class="post-metadata">

**Author:** ![gregm](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/bc79bd/32.png) [@gregm](https://www.ruby-forum.com/u/gregm)\
**Post date:** [February 15, 2010, 9:25am UTC](https://www.ruby-forum.com/t/compare-and-delete-element-from-an-array/183462/8 "2010-02-15T09:25:33Z")

</div>

2010/2/15 Greg Ma [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> ```
> array_of_tags.each do |tag|
> tags.delete_if {
> |x| x.name == tag
> puts x.name + "-"+ x.name.length.to_s
> puts tag + "-"+ tag.length.to_s
> puts "-----"
> }
> end
> puts tags
> 
> ```
> 
> end  
> end

This algorithm has roughly effort O(n^2) because you compare all pairs  
of elements.

I don’t know sizes of your data structures but here’s how I’d do it

require ‘set’

def remove\_tags(array\_of\_tags)  
unless array\_of\_tags.empty?  
aot = array\_of\_tags.to\_set  
tags.delete\_if {|t| aot.include? t.name}  
end

self  
end

The advantage is that Set has O(1) lookup because it uses hashing  
internally. It may not pay off for small data structures so you could  
as well do

def remove\_tags(array\_of\_tags)  
tags.delete\_if {|t| array\_of\_tags.include? t.name} unless  
array\_of\_tags.empty?  
self  
end

This one still has O(n^2) but since Array#include? is used which is  
implemented in C chances are that is faster than the variant with Set  
because the Set creation overhead is removed.

Kind regards

robert
