0

I have an Array that contains

arrTV = ['Thor: The Dark World', 'Ender's Game', 'Jackass Presents: Bad Grandpa', 'Last Vegas', 'Free Birds', 'Free Birds' ]

The last two elements are duplicates. I want to loop through the array and check if there exists a duplicate and I do not want to use .uniq

Please advice

I have tried something like this and it doesn't work

arrTV.each do |i|
  count = 0

  #if arrTV[i] == arrTV[i+1]
  #  puts "equal"
  #  count = count + 1
  #
  #end
  #puts count

  #if arrTV[i] = arrTV[i+1]
  #arrTV.delete_at(i+1)
  #end

end

Where am I going wrong ?

knut
  • 27,320
  • 6
  • 84
  • 112
napsterdsilva
  • 163
  • 1
  • 2
  • 14
  • 3
    Why don't you want to use `uniq`? – Alex.Bullard Nov 04 '13 at 23:19
  • There's some interesting solutions here: http://stackoverflow.com/questions/1532819/algorithm-efficient-way-to-remove-duplicate-integers-from-an-array – james246 Nov 04 '13 at 23:38
  • 1
    Below you posted a comment "...I then used arrTV.uniq, but that too didn't take off the duplicates.". You posted that well after @Michael posted his answer, in which he pointed out that you must escape all apostrophes, in particular, `'Ender\'s Game'`. Did you do that? If not, that explains a lot. Once that's done, I guarantee uniq will work. Alternatively, you could change all the single quotes to double quotes, except for the apostrophes (`"Ender's Game"). I recommend you do it that way. It only has to be done for words containing apostrophes, but better to do it for all. – Cary Swoveland Nov 05 '13 at 05:59

6 Answers6

3

This is not likely the most efficient, but it's easy to understand at a high level what is going on.

require 'set'

arrTV = ['Thor: The Dark World', 'Ender's Game', 'Jackass Presents: Bad Grandpa', 'Last Vegas', 'Free Birds', 'Free Birds' ]

arrTV.to_set.to_a
GregA100k
  • 1,385
  • 1
  • 11
  • 16
1

How about:

2.0.0-p247 :004 > arrTV = ['Thor: The Dark World', 'Ender\'s Game', 
'Jackass Presents: Bad Grandpa', 'Last Vegas', 'Free Birds', 'Free Birds' ]  
# (Note escaping the `'` in Ender`'`s)

2.0.0-p247 :009 > prev='xxxxx'
2.0.0-p247 :009 > new_array=[]

2.0.0-p247 :016 > arrTV.sort.each do |current|
2.0.0-p247 :017 >     if (current != prev)
2.0.0-p247 :018?>       new_array << current
2.0.0-p247 :018?>       puts current
2.0.0-p247 :019?>       prev=current
2.0.0-p247 :020?>     end
2.0.0-p247 :021?>   end
Ender's Game
Free Birds
Jackass Presents: Bad Grandpa
Last Vegas
Thor: The Dark World
Michael Durrant
  • 93,410
  • 97
  • 333
  • 497
  • i see the following error msg: comparison of String with Array failed (ArgumentError) ./features/feature_list/calabash_android_helper.rb:347:in `sort' ./features/feature_list/calabash_android_helper.rb:347:in `getSubHeader' ./features/feature_list/now_playing.rb:45:in `getSubHeaderList' ./features/step_definitions/nowPlaying_steps.rb:45:in `/^I should see list of SubHeader$/' features/box_office.feature:13:in `Then I should see list of SubHeader' – napsterdsilva Nov 05 '13 at 02:29
  • huh? I tried this is 1.9.3 and it worked there too. You are posting results from running spec files. You should post that too. – Michael Durrant Nov 05 '13 at 02:43
  • Hi Michael !! Thanks for your Time.. The Flow is as follows .. Cucumber : Then i Should See a list of Movies – napsterdsilva Nov 05 '13 at 03:13
  • Step Definition : def getSubHeader sleep(1) q = query("TextView marked:'Ratings'") # Boundary condition, this element is visible only after scrolled to bottom arrTV = Array.new(query("TextView id:'movieTitle'", :text)) while q.empty? performAction('scroll_down') sleep(1) if element_exists("TextView") arrTV.push(query("TextView id:'movieTitle'", :text)) end q = query("TextView marked:'Ratings'") end arrTV = arrTV.uniq puts arrTV.size puts arrTV end – napsterdsilva Nov 05 '13 at 03:20
1

You can do this:

arr = []
arrTV.each do |e|
     arr << e unless arr.include?(e)
end
#arr should now contains the same elements as arrTV.uniq does.

But then, why not use uniq? Homework maybe?

Automatico
  • 12,420
  • 9
  • 82
  • 110
1

I think you can use Array#| method, if you don't want to use Array#uniq method.

arr = %w(foo bar baz bar)
(arr | arr)
# => ["foo", "bar", "baz"]
Arup Rakshit
  • 116,827
  • 30
  • 260
  • 317
0

I will confine my remarks to your last sentence: "Where am I going wrong?"

arrTV = ['Thor: The Dark World', 'Ender's Game', 'Jackass Presents: Bad Grandpa', \
         'Last Vegas', 'Free Birds', 'Free Birds' ]

[Edit: As @Michael pointed out, you must escape all apostrophes in the elements of arrTV (in particular, 'Ender\'s Game'). Alternatively, you can can enclose the strings in double quotes:

arrTV = ["Thor: The Dark World", "Ender's Game", "Jackass Presents: Bad Grandpa", \
         "Last Vegas", "Free Birds", "Free Birds" ]

I would recommend doing the latter. End of Edit]

It appears you first tried this:

arrTV.each do |i|
  count = 0
  if arrTV[i] == arrTV[i+1]
    puts "equal"
    count = count + 1
  end
  puts count
end

The first time through the (do..end) block, i is set equal to the first element of arrTV, which is 'Thor: The Dark World', so you are attempting to execute

  if arrTV['Thor: The Dark World'] == arrTV['Thor: The Dark World'+1]

which will raise an error. Consider doing this instead

  if arrTV[count] == arrTV[count+1]

Better, but there are still a couple of problems. Firstly, every time the block is passed to an element of arrTV, count is reset to zero. You can fix that by moving count = 0 before arrTV.delete_at(i+1). Also, move puts count to the end of the if statement (right before end).

Secondly, what happens when count = 5? At that point you are executing

  if arrTV[5] == arrTV[6],

but arrTV only contains 6 elements, the last one indexed 5. arrTV[6] is not defined. There are many ways to fix this problem. One is to add:

  break if count == 5

after

  count = count + 1

It looks like you next tried to do this within the block

   if arrTV[i] = arrTV[i+1]
   arrTV.delete_at(i+1)

(Incidentally, notice that you want ==, not = in the first statement.) Even if we replace i with count, you are attempting to delete some elements of arrTV while interating over it. That's a no-no. What you need to do is start with this:

  (0..arrTV.size-2) each do |i|

with this, you no longer need count. Nor do you need to break out of the loop once you've processed the next-to-last element of arrTV. More importantly, since you are not iterating over the elements of arrTV, you can delete them within the loop:

   arrTV.delete_at(i+1)

(This way, you could also add elements to arrTV, or modify elements.) I will leave it to you to fix it from here. I would like to point out, however, that the approach you are taking will only eliminate duplicates if they are adjacent elements of arrTV. If order is unimportant, you need to modify your approach.

Lastly, one Ruby convention is to use only lower case letters for variable names, and to add underscores where necessary for readability. You might use something like arr_tv, rather than arrTV.

Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
  • Hi All, Thanks for your response. I am new to ruby. I am working with a tool to automate android app. The tool is called calabsh. Now, I scrolled one screen of the app from top to bottom to get a list of movies on the screen. I got the following list of elements into an array arrTV. I then used arrTV.uniq, but that too didnt take off the duplicates. I then used arrTV.length, arrTV.size, arrTV.count ..all returned 14 instead of 51 So I am using .uniq.. and nothing works. So thought of working on the elements in the array and take off duplicates. – napsterdsilva Nov 05 '13 at 02:14
  • The Array contains : Thor: The Dark World Ender's Game Jackass Presents: Bad Grandpa Last Vegas Free Birds Free Birds Gravity Captain Phillips 12 Years a Slave Cloudy with a Chance of Meatballs 2 The Counselor The Counselor Carrie Escape Plan Enough Said Insidious: Chapter 2 Prisoners Prisoners We're The Millers Baggage Claim Planes Rush Percy Jackson: Sea of Monsters Percy Jackson: Sea of Monsters I'm In Love With A Church Girl Lee Daniels' The Butler Runner Runner Krrish 3 Don Jon Don Jon About Time Instructions Not Included The Mortal Instruments: City of Bones All Is Lost Machete Kills – napsterdsilva Nov 05 '13 at 02:15
0

You could use the Set Intersection method with the Ampersand (&) Operator :

arrTV = ['Thor: The Dark World', 'Ender\'s Game', 
'Jackass Presents: Bad Grandpa', 'Last Vegas', 'Free Birds', 'Free Birds' ] 

def unique(array)
  array & array
end

result = unique(arrTV)
print result # => ["Thor: The Dark World", "Ender's Game", "Jackass Presents: Bad Grandpa", "Last Vegas", "Free Birds"]

With Set Intersection (using Intersect Operator &), a new array is returned containing elements common to the two arrays, with duplicates removed.

In the method, the & is placed between the two arrays we want to evaluate. In this example, we pass one array into the method but evaluate that array against itself to remove any duplicates.

tmlen
  • 8,533
  • 5
  • 31
  • 84