how to test if an array include only two items ?


(Abdel Latif) #1

Hi,

I would like to see if

array_status = ['hired','hired','provisionally hire','hired','hired',
'provisionally
hire', 'provisionally hire','hired']

has only these two strings ('hired' and 'provisionally hire') , both of
them or one of them, even repeated.

but not any other things.

Thanks.


(Rob Biedenharn) #2

Kinda ugly, but gives the answer to the question that you seem to be asking:

(array_status.uniq - ['hired','provisionally hire']).empty?

-Rob

···

On 2018-Feb-21, at 15:15 , Abdel Latif <mlotfi2005@gmail.com> wrote:

Hi,

I would like to see if

array_status = ['hired','hired','provisionally hire','hired','hired', 'provisionally hire', 'provisionally hire','hired']

has only these two strings ('hired' and 'provisionally hire') , both of them or one of them, even repeated.

but not any other things.

Thanks.


(Abdel Latif) #3

Thanks you Rob, it worked, I testing a table with selenium, and I have to
proof that that column has only those two strings.

I am a new in ruby,
please bear with me if I ask ugly questions.
Thanks again.

···

On Wed, Feb 21, 2018 at 3:20 PM, Rob Biedenharn <rob.biedenharn@gmail.com> wrote:

On 2018-Feb-21, at 15:15 , Abdel Latif <mlotfi2005@gmail.com> wrote:

Hi,

I would like to see if

array_status = ['hired','hired','provisionally hire','hired','hired', 'provisionally
hire', 'provisionally hire','hired']

has only these two strings ('hired' and 'provisionally hire') , both of
them or one of them, even repeated.

but not any other things.

Thanks.

Kinda ugly, but gives the answer to the question that you seem to be
asking:

(array_status.uniq - ['hired','provisionally hire']).empty?

-Rob

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>


(Steve Turczyn) #4

Just to add... You don't actually need #uniq

Cheers Steve

⁣Sent from BlueMail ​

···

On 21 Feb 2018, 20:20, at 20:20, Rob Biedenharn <rob.biedenharn@gmail.com> wrote:

On 2018-Feb-21, at 15:15 , Abdel Latif <mlotfi2005@gmail.com> wrote:

Hi,

I would like to see if

array_status = ['hired','hired','provisionally hire','hired','hired',

'provisionally hire', 'provisionally hire','hired']

has only these two strings ('hired' and 'provisionally hire') , both

of them or one of them, even repeated.

but not any other things.

Thanks.

Kinda ugly, but gives the answer to the question that you seem to be
asking:

(array_status.uniq - ['hired','provisionally hire']).empty?

-Rob

------------------------------------------------------------------------

Unsubscribe:
<mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>


(Rob Biedenharn) #5

Oh, that's a bit different. I have a higher threshold for acceptable "ugliness" for code that's part of a test than for code that's "in production".

The only thing I'd do a bit differently for a test is ensure that I could see what's actually present, though unexpected, if the test fails. (Though if you have a screen capture or something, that might be sufficient.)

-Rob

···

On 2018-Feb-21, at 15:32 , Abdel Latif <mlotfi2005@gmail.com> wrote:

Thanks you Rob, it worked, I testing a table with selenium, and I have to proof that that column has only those two strings.

I am a new in ruby,
please bear with me if I ask ugly questions.
Thanks again.

On Wed, Feb 21, 2018 at 3:20 PM, Rob Biedenharn <rob.biedenharn@gmail.com <mailto:rob.biedenharn@gmail.com>> wrote:

On 2018-Feb-21, at 15:15 , Abdel Latif <mlotfi2005@gmail.com <mailto:mlotfi2005@gmail.com>> wrote:

Hi,

I would like to see if

array_status = ['hired','hired','provisionally hire','hired','hired', 'provisionally hire', 'provisionally hire','hired']

has only these two strings ('hired' and 'provisionally hire') , both of them or one of them, even repeated.

but not any other things.

Thanks.

Kinda ugly, but gives the answer to the question that you seem to be asking:

(array_status.uniq - ['hired','provisionally hire']).empty?

-Rob

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org <mailto:ruby-talk-request@ruby-lang.org>?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>


(Nicola Mingotti) #6

Since you are a beginner I would follow a more "didactic" approach;)
As other have said you can write that code in one line ... well, this is the opposite,
verbose and "as readable as possible".

# INPUT:
# allStates -> array
# goodStates -> array
# WHAT:
# returns "good" if all elemenst of "allStates" are contained into
# "goodStates" array. Otherwise returns "bad"
# EXAMPLES:
# checkStatus(["a","a","b"], ["a","b"])
# => "good"
# checkStatus(["a","a","b","c"], ["a","b"])
# => "bad"
def checkStatus(allStates, goodStates)
hasGoodStates = false
allStates.each do |x|
if goodStates.include? x then
hasGoodStates = true
else
return "bad"
end
end
if hasGoodStates == true then
return "good"
else
return "bad"
end
end

···

On 02/21/18 21:20, Rob Biedenharn wrote:

['hired','hired','provisionally hire','hired','hired',

--
--------------------------
Dr. Nicola Mingotti
R&D - Borghi Srl
CTO - BondInsider
--------------------------


(Steve Turczyn) #7

One functional difference between the other solutions and the below
solution Nicola proposes is whether an empty allStates array would be
considered pass or failure. Nicola's code assumes an empty array is
failure. I guess the OP may want to decide how he wants the empty array
case handled.
Ruby good practice tends to encourage a holistic view of arrays,
generally avoiding #each iteration, so I'd encourage a beginner, on
refactoring, to look at whether an #each is needed and whether state
variables like the "hasGoodStates" Is needed.
And if I had to use "hasGoodStates" variable and if it only contains a
boolean value, then I would replace "if hasGoodStates == true" with"if
hasGoodStates"
Finally, instead of returning the strings "good" and "bad" which are a
pain to test for, I'd expect a method that returns a boolean (and to
reflect this, I would end the method name with a question mark)
So I'd be more likely to suggest the following

def no_unexpected?(all_states, good_states)
  return false if all_states.empty? # needed if we assume empty test
  array is bad all_states.any? { |element| !good_states.include? element }
end

Although I'm still partial to the subtraction method :slight_smile:

def no_unexpected?(all_states, good_states)
  return false if all_states.empty? # needed if we assume empty test
  array is bad (all_states - good_states).empty?
end

And you can tighten up with a ternary and (I think) without sacrificing
too much readability.
def no_unexpected?(all_states, good_states)
  all_states.empty? ? false : (all_states - good_states).empty?
end

Use the method's boolean response to control decision flow.

if no_unexpected?(array_1, array_2)
  # stuff to do if things are ok
else
  # stuff to do if things aren't ok
end

···

On Thu, Feb 22, 2018, at 9:34 AM, Nicola Mingotti wrote:

Since you are a beginner I would follow a more "didactic" approach;)
As other have said you can write that code in one line ... well, this
is the opposite,> verbose and "as readable as possible".

# INPUT:
# allStates -> array
# goodStates -> array
# WHAT:
# returns "good" if all elemenst of "allStates" are contained into
# "goodStates" array. Otherwise returns "bad"
# EXAMPLES:
# checkStatus(["a","a","b"], ["a","b"])
# => "good"
# checkStatus(["a","a","b","c"], ["a","b"])
# => "bad"
def checkStatus(allStates, goodStates)
  hasGoodStates = false
  allStates.each do |x|
    if goodStates.include? x then
      hasGoodStates = true
    else
      return "bad"
    end
  end
  if hasGoodStates == true then
    return "good"
  else
    return "bad"
  end
end

On 02/21/18 21:20, Rob Biedenharn wrote:

['hired','hired','provisionally hire','hired','hired',>

-- -------------------------- Dr. Nicola Mingotti R&D - Borghi Srl CTO
- BondInsider -------------------------->
Unsubscribe: <mailto:ruby-talk-request@ruby-
lang.org?subject=unsubscribe>> <http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>


(Nicola Mingotti) #8

In my opinion, given the proponents example, an empty "allStates" must
result in "bad". But, guys, that is not the point, he did not tell anything
about special cases.

Returning strings is very good for learning IMO.

Also some "return" could be cutted, some lines compressed,
change a search into the array "goodStates" with hash search, that would
change the computational complexity of this code form
"n*m" to "n", where "n" is ... oh, ok, you know.

The proponent can change it as he likes, one he understands how it works
and his knowledge progresses.

Evoiding "each", I completely disagree on this point.
Once you hide the loops it is hard to say where your code spend time.

This are just my opinions, I will not enter a style debate;)

Bye
Nicola

···

On 02/22/18 11:17, Steve Turczyn wrote:

One functional difference between the other solutions and the below solution Nicola proposes is whether an empty allStates array would be considered pass or failure. Nicola's code assumes an empty array is failure. I guess the OP may want to decide how he wants the empty array case handled.

Ruby good practice tends to encourage a holistic view of arrays, generally avoiding #each iteration, so I'd encourage a beginner, on refactoring, to look at whether an #each is needed and whether state variables like the "hasGoodStates" Is needed.

And if I had to use "hasGoodStates" variable and if it only contains a boolean value, then I would replace "if hasGoodStates == true" with"if hasGoodStates"

Finally, instead of returning the strings "good" and "bad" which are a pain to test for, I'd expect a method that returns a boolean (and to reflect this, I would end the method name with a question mark)

So I'd be more likely to suggest the following

def no_unexpected?(all_states, good_states)
return false if all_states.empty? # needed if we assume empty test array is bad
all_states.any? { |element| !good_states.include? element }
end

Although I'm still partial to the subtraction method :slight_smile:

def no_unexpected?(all_states, good_states)
return false if all_states.empty? # needed if we assume empty test array is bad
(all_states - good_states).empty?
end

And you can tighten up with a ternary and (I think) without sacrificing too much readability.

def no_unexpected?(all_states, good_states)
all_states.empty? ? false : (all_states - good_states).empty?
end

Use the method's boolean response to control decision flow.

if no_unexpected?(array_1, array_2)
# stuff to do if things are ok
else
# stuff to do if things aren't ok
end

On Thu, Feb 22, 2018, at 9:34 AM, Nicola Mingotti wrote:

Since you are a beginner I would follow a more "didactic" approach;)
As other have said you can write that code in one line ... well, this is the opposite,
verbose and "as readable as possible".

# INPUT:
# allStates -> array
# goodStates -> array
# WHAT:
# returns "good" if all elemenst of "allStates" are contained into
# "goodStates" array. Otherwise returns "bad"
# EXAMPLES:
# checkStatus(["a","a","b"], ["a","b"])
# => "good"
# checkStatus(["a","a","b","c"], ["a","b"])
# => "bad"
def checkStatus(allStates, goodStates)
hasGoodStates = false
allStates.each do |x|
if goodStates.include? x then
hasGoodStates = true
else
return "bad"
end
end
if hasGoodStates == true then
return "good"
else
return "bad"
end
end

On 02/21/18 21:20, Rob Biedenharn wrote:

['hired','hired','provisionally hire','hired','hired',

--
--------------------------
Dr. Nicola Mingotti
R&D - Borghi Srl
CTO - BondInsider
--------------------------

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>

--
--------------------------
Dr. Nicola Mingotti
R&D - Borghi Srl
CTO - BondInsider
--------------------------


(Steve Turczyn) #9

"Tim Toady" :slight_smile:

···

On Thu, Feb 22, 2018, at 11:08 AM, Nicola Mingotti wrote:

In my opinion, given the proponents example, an empty "allStates" must> result in "bad". But, guys, that is not the point, he did not tell
> about special cases.

Returning strings is very good for learning IMO.

Also some "return" could be cutted, some lines compressed,
change a search into the array "goodStates" with hash search,
that would> change the computational complexity of this code form
"n*m" to "n", where "n" is ... oh, ok, you know.

The proponent can change it as he likes, one he understands how
it works> and his knowledge progresses.

Evoiding "each", I completely disagree on this point.
Once you hide the loops it is hard to say where your code spend time.>
This are just my opinions, I will not enter a style debate;)

Bye
Nicola

On 02/22/18 11:17, Steve Turczyn wrote:

One functional difference between the other solutions and the below
solution Nicola proposes is whether an empty allStates array would be
considered pass or failure. Nicola's code assumes an empty array is
failure. I guess the OP may want to decide how he wants the empty
array case handled.>>
Ruby good practice tends to encourage a holistic view of arrays,
generally avoiding #each iteration, so I'd encourage a beginner, on
refactoring, to look at whether an #each is needed and whether state
variables like the "hasGoodStates" Is needed.>>
And if I had to use "hasGoodStates" variable and if it only contains
a boolean value, then I would replace "if hasGoodStates == true"
with"if hasGoodStates">>
Finally, instead of returning the strings "good" and "bad" which are
a pain to test for, I'd expect a method that returns a boolean (and
to reflect this, I would end the method name with a question mark)>>
So I'd be more likely to suggest the following

def no_unexpected?(all_states, good_states)
  return false if all_states.empty? # needed if we assume empty test
  array is bad>> all_states.any? { |element| !good_states.include? element }
end

Although I'm still partial to the subtraction method :slight_smile:

def no_unexpected?(all_states, good_states)
  return false if all_states.empty? # needed if we assume empty test
  array is bad>> (all_states - good_states).empty?
end

And you can tighten up with a ternary and (I think) without
sacrificing too much readability.>>
def no_unexpected?(all_states, good_states)
  all_states.empty? ? false : (all_states - good_states).empty?
end

Use the method's boolean response to control decision flow.

if no_unexpected?(array_1, array_2)
  # stuff to do if things are ok
else
  # stuff to do if things aren't ok
end

On Thu, Feb 22, 2018, at 9:34 AM, Nicola Mingotti wrote:

Since you are a beginner I would follow a more "didactic" approach;)>>> As other have said you can write that code in one line ... well,
this is the opposite,>>> verbose and "as readable as possible".

# INPUT:
# allStates -> array
# goodStates -> array
# WHAT:
# returns "good" if all elemenst of "allStates" are contained into>>> # "goodStates" array. Otherwise returns "bad"
# EXAMPLES:
# checkStatus(["a","a","b"], ["a","b"])
# => "good"
# checkStatus(["a","a","b","c"], ["a","b"])
# => "bad"
def checkStatus(allStates, goodStates)
  hasGoodStates = false
  allStates.each do |x|
    if goodStates.include? x then
      hasGoodStates = true
    else
      return "bad"
    end
  end
  if hasGoodStates == true then
    return "good"
  else
    return "bad"
  end
end

On 02/21/18 21:20, Rob Biedenharn wrote:

['hired','hired','provisionally hire','hired','hired',>>>

-- -------------------------- Dr. Nicola Mingotti R&D - Borghi Srl
CTO - BondInsider --------------------------

Unsubscribe: <mailto:ruby-talk-request@ruby-
lang.org?subject=unsubscribe>>>> <http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>

Unsubscribe: <mailto:ruby-talk-request@ruby-
lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>

-- -------------------------- Dr. Nicola Mingotti R&D - Borghi Srl CTO
- BondInsider --------------------------


(Robert K.) #10

One functional difference between the other solutions and the below solution
Nicola proposes is whether an empty allStates array would be considered pass
or failure. Nicola's code assumes an empty array is failure. I guess the OP
may want to decide how he wants the empty array case handled.

I think that assumption is making things unnecessary complicated
because it changes the semantics of the false return.

Ruby good practice tends to encourage a holistic view of arrays, generally
avoiding #each iteration, so I'd encourage a beginner, on refactoring, to
look at whether an #each is needed and whether state variables like the
"hasGoodStates" Is needed.

Agree.

And if I had to use "hasGoodStates" variable and if it only contains a
boolean value, then I would replace "if hasGoodStates == true" with"if
hasGoodStates"

Absolutely!

Finally, instead of returning the strings "good" and "bad" which are a pain
to test for, I'd expect a method that returns a boolean (and to reflect
this, I would end the method name with a question mark)

So I'd be more likely to suggest the following

def no_unexpected?(all_states, good_states)
  return false if all_states.empty? # needed if we assume empty test array
is bad

That test complicates things unnecessarily. Also, it changes the
consistency of the return value.

  all_states.any? { |element| !good_states.include? element }
end

There is too much negation going on. This is confusing - at least for me.

I would just use simple logic - the result can easily be negated if needed:

irb(main):001:0> array_status = ['hired','hired','provisionally
hire','hired','hired', 'provisionally hire', 'provisionally
hire','hired']
=> ["hired", "hired", "provisionally hire", "hired", "hired",
"provisionally hire", "provisionally hire", "hired"]
irb(main):002:0> filter = ['hired', 'provisionally hire']
=> ["hired", "provisionally hire"]
irb(main):003:0> array_status.all? {|x| filter.include? x}
=> true

As a method

def all_valid?(enum, filter)
  enum.all? {|x| filter.include? x}
end

But I doubt this little piece of code is worthwhile to be defined as a method.

Although I'm still partial to the subtraction method :slight_smile:

def no_unexpected?(all_states, good_states)
  return false if all_states.empty? # needed if we assume empty test array
is bad
  (all_states - good_states).empty?
end

Disadvantage of the subtraction method is that all elements must be
read. This can make a difference for large inputs. The approach with
#any? or #all? allows to exit as soon as one outlier is found.

And you can tighten up with a ternary and (I think) without sacrificing too
much readability.

def no_unexpected?(all_states, good_states)
  all_states.empty? ? false : (all_states - good_states).empty?
end

Again, the ternary operator makes this unnecessary hard to read. You can just do

def no_unexpected?(all_states, good_states)
  !all_states.empty? && (all_states - good_states).empty?
end

But see remark above. And btw. did you notice that your method is way
more generic than the current use case? That is why I picked more
generalized parameter names.

Since you are a beginner I would follow a more "didactic" approach;)
As other have said you can write that code in one line ... well, this is the
opposite,
verbose and "as readable as possible".

I disagree that this is "as readable as possible". The longer a method
and the more code it contains the more work the brain has to do. This
is especially true the more variables are in use because variables
store state. And in this case it is totally superfluous.

# INPUT:
# allStates -> array
# goodStates -> array
# WHAT:
# returns "good" if all elemenst of "allStates" are contained into
# "goodStates" array. Otherwise returns "bad"
# EXAMPLES:
# checkStatus(["a","a","b"], ["a","b"])
# => "good"
# checkStatus(["a","a","b","c"], ["a","b"])
# => "bad"
def checkStatus(allStates, goodStates)
  hasGoodStates = false
  allStates.each do |x|
    if goodStates.include? x then
      hasGoodStates = true
    else
      return "bad"
    end
  end
  if hasGoodStates == true then

Don't EVER compare boolean values with a boolean constant! This is
error prone! Do not let yourself get into that habit, even in
languages which have exactly two boolean values. Ruby is not one of
them. It is especially bad showing this as an example to a "beginner".
in case someone wonders, here's why:

irb(main):004:0> [true, false, nil, 123, "hello"].map {|b| if b ==
true; "TRUE"; else "false"; end}
=> ["TRUE", "false", "false", "false", "false"]
irb(main):005:0> [true, false, nil, 123, "hello"].map {|b| if b;
"TRUE"; else "false"; end}
=> ["TRUE", "false", "false", "TRUE", "TRUE"]

Kind regards

robert

···

On Thu, Feb 22, 2018 at 11:17 AM, Steve Turczyn <steve@turczyn.co.uk> wrote:

On Thu, Feb 22, 2018, at 9:34 AM, Nicola Mingotti wrote:

--
[guy, jim, charlie].each {|him| remember.him do |as, often| as.you_can
- without end}
http://blog.rubybestpractices.com/


(Robert K.) #11

In my opinion, given the proponents example, an empty "allStates" must
result in "bad". But, guys, that is not the point, he did not tell anything
about special cases.

Then why introduce it?

Returning strings is very good for learning IMO.

... but does not allow the return value to be used in a boolean
context without additional work (comparing it with the value supposed
to signify true or false).

Also some "return" could be cutted, some lines compressed,
change a search into the array "goodStates" with hash search, that would
change the computational complexity of this code form
"n*m" to "n", where "n" is ... oh, ok, you know.

The proponent can change it as he likes, one he understands how it works
and his knowledge progresses.

As for a verbose version that could look like this:

def all_valid?(enum, filter)
  enum.each {|x| return false unless filter.include? x}
  true # not needed as enum is already equivalent to true
end

Advantage is that it shows the short circuiting when the element is invalid.

Evoiding "each", I completely disagree on this point.

I agree to your disagreement. There is nothing more holistic using
#any? than #each.

Once you hide the loops it is hard to say where your code spend time.

#each is hiding the loop as much or as little as #any? and #all? - so
either is the same and we can pick the best tool for the job.

This are just my opinions, I will not enter a style debate;)

I do not think this is about style - at least only partly. There are
some objective factors that can be used to compare and value solutions
against each other.

Kind regards

robert

···

On Thu, Feb 22, 2018 at 12:08 PM, Nicola Mingotti <nmingotti@gmail.com> wrote:

--
[guy, jim, charlie].each {|him| remember.him do |as, often| as.you_can
- without end}
http://blog.rubybestpractices.com/


(Ryan Davis) #12

Hi,

I would like to see if

array_status = ['hired','hired','provisionally hire','hired','hired', 'provisionally hire', 'provisionally hire','hired']

has only these two strings ('hired' and 'provisionally hire') , both of them or one of them, even repeated.

I think (almost) all of these suggestions are too complicated and don’t describe themselves at a glance. I don’t want to have to think too much looking over someone else’s code.

Given what you want:

>> want = %w[a b]

versus what you have:

>> have = %w[a b b a]

do you have ONLY what you want?

>> want | have == want
=> true

and when you don’t:

···

On Feb 21, 2018, at 12:15, Abdel Latif <mlotfi2005@gmail.com> wrote:

>> have = %w[a b c b a]

>> want | have == want
=> false


(Steve Turczyn) #13

Very clean, but doesn’t this fail for?

have = %w( a a a a)

> 
> > 
> >  Hi,
> > 
> >  I would like to see if
> > 
> >  array_status = ['hired','hired','provisionally hire','hired','hired', 'provisionally hire', 'provisionally hire','hired']
> > 
> >  has only these two strings ('hired' and 'provisionally hire') , both of them or one of them, even repeated.
> 
> I think (almost) all of these suggestions are too complicated and don’t describe themselves at a glance. I don’t want to have to think too much looking over someone else’s code.
> 
> Given what you want:
> 
> > > > want = %w[a b]
> 
> 
> versus what you have:
> 
> > > > have = %w[a b b a]
> 
> 
> do you have ONLY what you want?
> 
> > > > want | have == want
> > => true
> 
> and when you don’t:
> 
> > > > have = %w[a b c b a]
> 
> > > > want | have == want
> > => false
> 
> 
> Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
> <[http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk](http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk)>
···

Sent from BlueMail
On 24 Feb 2018, at 01:12, Ryan Davis ryand-ruby@zenspider.com wrote:

On Feb 21, 2018, at 12:15, Abdel Latif mlotfi2005@gmail.com wrote: