# An array problem

**URL:** <https://www.ruby-forum.com/t/an-array-problem/164570>\
**Category:** Ruby\
**Created:** [April 2, 2009, 5:48pm UTC](https://www.ruby-forum.com/t/an-array-problem/164570 "2009-04-02T17:48:24Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![georgeuoa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/7ab992/32.png) [@georgeuoa](https://www.ruby-forum.com/u/georgeuoa)\
**Post date:** [April 2, 2009, 5:48pm UTC](https://www.ruby-forum.com/t/an-array-problem/164570/1 "2009-04-02T17:48:24Z")

</div>

Hi  
i have a 3 arrays(A,B,C) which are results of some analysis.  
Array A has all members such that array B and C are actually subsets of  
A. The order of elements in array A is important.

What i want is to list all members of A such that if an element in A is  
a found in B or C produce a report such as

element1 -b  
element2 -b  
element3 -c  
element4 -b  
…

where the order of elements in the report is as was in array A.

my rather silly implentation was  
A.each do |element|  
if B.detect(element)  
puts “#{element}- b”  
end  
end

however i don’t think this is the right way to do it since it does not  
give me the designed result. Can someone help me spot the bug?

Thank you  
George

---

<div class="post-metadata">

**Author:** ![georgeuoa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/7ab992/32.png) [@georgeuoa](https://www.ruby-forum.com/u/georgeuoa)\
**Post date:** [April 2, 2009, 6:24pm UTC](https://www.ruby-forum.com/t/an-array-problem/164570/2 "2009-04-02T18:24:21Z")

</div>

2009/4/2 George G. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> i have a 3 arrays(A,B,C) which are results of some analysis.

I’d rather not make those constants (A,B,C) because they aren’t as you  
stated.

> …
> 
> however i don’t think this is the right way to do it since it does not  
> give me the designed result. Can someone help me spot the bug?

You want #include? instead of #detect:

a.each do |el|  
case  
when b.include? el  
puts “#{el} -b”  
when c.include? el  
puts “#{el} -c”  
end  
end

Another hint: if A is really large (say 10\_000 elements or more) it  
might be more efficient to convert B and C into Sets which have faster  
inclusion test.

Or do it this way:

occurrences = {}

{b =\> “b”, c =\> “c”}.each do |ar,label|  
ar.each {|el| occurrences[el] = label}  
end

a.each do |el|  
label = occurrences[el] and  
puts “#{el} -#{label}”  
end

Kind regards

robert

---

<div class="post-metadata">

**Author:** ![georgeuoa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/7ab992/32.png) [@georgeuoa](https://www.ruby-forum.com/u/georgeuoa)\
**Post date:** [April 3, 2009, 7:09am UTC](https://www.ruby-forum.com/t/an-array-problem/164570/3 "2009-04-03T07:09:55Z")

</div>

> You want #include? instead of #detect:
> 
> a.each do |el|  
> case  
> when b.include? el  
> puts “#{el} -b”  
> when c.include? el  
> puts “#{el} -c”  
> end  
> end

Thanks a lot Robert, However this solution does not seem to preserve the  
order in of array a.  
for example if array a contained  
a = [“x”,“y”,“z”,“f”]  
b = [“y”,“z”]  
c = [“x”,“f”]

the result should be

x-c  
y-b  
z-b  
f-c

Thanks  
GG

---

<div class="post-metadata">

**Author:** ![georgeuoa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/7ab992/32.png) [@georgeuoa](https://www.ruby-forum.com/u/georgeuoa)\
**Post date:** [April 3, 2009, 8:30am UTC](https://www.ruby-forum.com/t/an-array-problem/164570/4 "2009-04-03T08:30:59Z")

</div>

On 03.04.2009 07:09, George G. wrote:

> y-b  
> z-b  
> f-c

I don’t see how the order in a could not be preserved. Please check  
again oder provide full code.

Kind regards

robert

---

<div class="post-metadata">

**Author:** ![georgeuoa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/7ab992/32.png) [@georgeuoa](https://www.ruby-forum.com/u/georgeuoa)\
**Post date:** [April 3, 2009, 10:17am UTC](https://www.ruby-forum.com/t/an-array-problem/164570/5 "2009-04-03T10:17:34Z")

</div>

Robert K. wrote:

> I don’t see how the order in a could not be preserved. Please check  
> again oder provide full code.

Here is the code  
#original list  
@list\_of\_names

#mcl.total\_clusters provides a count for the number of clusters #or  
arrays available(a.k.a, my b and c in the previous #descriptions)

#an iterator that counts the number of arrays available(subsets #of  
@cluster\_members  
mcl.total\_clusters.times do |i|  
cluster\_members = mcl.cluster\_members\_for(i)

@list\_of\_names.each do |el|  
case  
when cluster\_members.include?(el)  
puts “#{el} - #{i}”  
end  
end  
end

Given: @list\_of\_names =  
[10Atig18,10Atig8,10Atig7,10Atig3,10Btig15,10Btig11,10Btig1],

and cluster b=[10Atig8,10Atig3,10Btig1] while the rest of the members  
belonged to cluster c

produce a report such that  
10Atig18 -c  
10Atig8 -b  
10Atig7 -c  
10Atig3 -b  
10Btig15 -c  
10Btig11 -c  
10Btig1 -b

The implementation above produces this,  
10Atig8 -b  
10Atig3 -b  
10Btig1 -b  
10Atig18 -c  
10Atig7 -c  
10Btig15 -c  
10Btig11 -c

which is not what is required.

---

<div class="post-metadata">

**Author:** ![georgeuoa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/7ab992/32.png) [@georgeuoa](https://www.ruby-forum.com/u/georgeuoa)\
**Post date:** [April 3, 2009, 10:55am UTC](https://www.ruby-forum.com/t/an-array-problem/164570/6 "2009-04-03T10:55:12Z")

</div>

Robert K. wrote:

> George, you claimed that the code _I_ presented does not maintain order.  
> Now you present totally different code as “proof”. The error is in  
> _your_ code. Btw, you also did not state that the number of cluster  
> arrays (b and c) is not fixed which is of course why you could not use  
> the bit you claimed would not maintain order. Please go back to my  
> original posting - you’ll find building blocks for a solution there.  
> I’ll leave the rest to you.

True, the error is in my code. Thank you for providing the clues.

---

<div class="post-metadata">

**Author:** ![georgeuoa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/7ab992/32.png) [@georgeuoa](https://www.ruby-forum.com/u/georgeuoa)\
**Post date:** [April 3, 2009, 5:05pm UTC](https://www.ruby-forum.com/t/an-array-problem/164570/7 "2009-04-03T17:05:02Z")

</div>

On Thu, Apr 2, 2009 at 9:23 AM, Robert K.  
[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > a found in B or C produce a report such as  
> > my rather silly implentation was
> 
> a.each do |el|  
> Â case  
> Â Â when b.include? el  
> Â Â Â puts “#{el} -b”  
> Â Â when c.include? el  
> Â Â Â puts “#{el} -c”  
> Â end  
> end

Neither ruby 1.8.6 (in IRB) or Jruby 1.2.0 (in jirb\_swing) likes this  
without parenthesizing the argument to include? in the when clauses,  
but a bigger problem is that if both b and c include a value it will  
only print that b did, since when clauses are exclusive.

If its not essential to preprocess the arrays as in your second  
approach, the following works:

puts a.map { |el|  
{b=\>‘b’,c=\>‘c’}.map { |arr, label|  
“#{el} -#{label}” if arr.include?(el)  
}  
}.flatten.compact

---

<div class="post-metadata">

**Author:** ![georgeuoa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/7ab992/32.png) [@georgeuoa](https://www.ruby-forum.com/u/georgeuoa)\
**Post date:** [April 3, 2009, 10:40am UTC](https://www.ruby-forum.com/t/an-array-problem/164570/8 "2009-04-03T10:40:28Z")

</div>

On 03.04.2009 10:17, George G. wrote:

> arrays available(a.k.a, my b and c in the previous #descriptions)  
> end  
> produce a report such that  
> 10Atig3 -b  
> 10Btig1 -b  
> 10Atig18 -c  
> 10Atig7 -c  
> 10Btig15 -c  
> 10Btig11 -c
> 
> which is not what is required.

George, you claimed that the code _I_ presented does not maintain order.  
Now you present totally different code as “proof”. The error is in  
_your_ code. Btw, you also did not state that the number of cluster  
arrays (b and c) is not fixed which is of course why you could not use  
the bit you claimed would not maintain order. Please go back to my  
original posting - you’ll find building blocks for a solution there.  
I’ll leave the rest to you.

Regards

robert

---

<div class="post-metadata">

**Author:** ![georgeuoa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/7ab992/32.png) [@georgeuoa](https://www.ruby-forum.com/u/georgeuoa)\
**Post date:** [April 3, 2009, 6:21pm UTC](https://www.ruby-forum.com/t/an-array-problem/164570/9 "2009-04-03T18:21:12Z")

</div>

On 03.04.2009 17:03, Christopher D. wrote:

> > > What i want is to list all members of A such that if an element in A is
> 
> without parenthesizing the argument to include? in the when clauses,  
> Right, I should have made the check. Thank you for pointing this out.

> but a bigger problem is that if both b and c include a value it will  
> only print that b did, since when clauses are exclusive.

This is not a problem of my code but in the problem specification.  
There was no statement about whether elements can occur in multiple of  
the subsets and if so, whether there is any priority defined. Since  
maintaining original order was stated important reporting an element  
more than once was not an option for me.

> If its not essential to preprocess the arrays as in your second  
> approach, the following works:
> 
> puts a.map { |el|  
> {b=\>‘b’,c=\>‘c’}.map { |arr, label|  
> “#{el} -#{label}” if arr.include?(el)  
> }  
> }.flatten.compact

I always find it inelegant to produce nested Arrays which can contain  
nils and then getting rid of them using flatten and compact. That’s  
mostly an issue of personal taste but in cases where there can be many  
nils compared to non nils this is also about efficiency.

Apropos: in your code you’ll create the same Hashes all the time. You  
could at least factor that out.

Kind regards

robert
