Array#index block and rdetect

T

trans. (T. Onoma)

Tiny RCR suggestion:

Array#index optionally take a block like Enumerable#detect does.

['a','b','c'].index{|e| e == 'b'} # => 1
['a','b','c'].index{|e| e == 'c'} # => 2
['a','a','a'].index{|e| e == 'a'} # => 0
['a','a','a'].index{|e| e == 'b'} # => nil

Question: why isn't #index a method of Enumerable, considering
#each_with_index is? (FYI: 'alias find detect'.)

Lastly, what about an rdetect?

--
( o _ カラム(Pakistan)
// trans.
/ \ (e-mail address removed)

I don't give a damn for a man that can only spell a word one way.
-Mark Twain
 
R

Robert Klemme

trans. (T. Onoma) said:
Tiny RCR suggestion:

Array#index optionally take a block like Enumerable#detect does.

['a','b','c'].index{|e| e == 'b'} # => 1
['a','b','c'].index{|e| e == 'c'} # => 2
['a','a','a'].index{|e| e == 'a'} # => 0
['a','a','a'].index{|e| e == 'b'} # => nil

Question: why isn't #index a method of Enumerable, considering
#each_with_index is? (FYI: 'alias find detect'.)

Because not all collections keep a definite order as Array does. For
example, hashes do not keep any certain order of elements hence indexing
does not make any sense.
Lastly, what about an rdetect?

Not in Enumerable because each only iterates in one direction. (Ok, you
could go through it an output the last but that would not work for
Enumerables that return infinite elements.)

Regards

robert
 
T

trans. (T. Onoma)

Tiny RCR suggestion:

Array#index optionally take a block like Enumerable#detect does.

['a','b','c'].index{|e| e == 'b'} # => 1
['a','b','c'].index{|e| e == 'c'} # => 2
['a','a','a'].index{|e| e == 'a'} # => 0
['a','a','a'].index{|e| e == 'b'} # => nil

But this Array#index {block) is acceptable, yes?
Because not all collections keep a definite order as Array does. For
example, hashes do not keep any certain order of elements hence indexing
does not make any sense.

Couldn't the index of a hash be considered the key? So the block of #index
when applied is the value. i.e.

{:a=>'a',:b=>'b',:c=>'b'}.index{|e| e == 'b'} # => :b

But then, of course, there would be no telling which key you might get.
Suppose that could be considered a problem.
Not in Enumerable because each only iterates in one direction. (Ok, you
could go through it an output the last but that would not work for
Enumerables that return infinite elements.)

I see.

Hmm... sometimes it seems like these are quite categorized as finely as they
might be.

T.

--
( o _ カラãƒ
// trans.
/ \ (e-mail address removed)

I don't give a damn for a man that can only spell a word one way.
-Mark Twain
 
Y

Yukihiro Matsumoto

Hi,

In message "Re: Array#index block and rdetect"

|> > Array#index optionally take a block like Enumerable#detect does.
|> >
|> > ['a','b','c'].index{|e| e == 'b'} # => 1
|> > ['a','b','c'].index{|e| e == 'c'} # => 2
|> > ['a','a','a'].index{|e| e == 'a'} # => 0
|> > ['a','a','a'].index{|e| e == 'b'} # => nil
|
|But this Array#index {block) is acceptable, yes?

Along with assoc and rassoc. I will consider this idea.

matz.
 
R

Robert Klemme

trans. (T. Onoma) said:
Tiny RCR suggestion:

Array#index optionally take a block like Enumerable#detect does.

['a','b','c'].index{|e| e == 'b'} # => 1
['a','b','c'].index{|e| e == 'c'} # => 2
['a','a','a'].index{|e| e == 'a'} # => 0
['a','a','a'].index{|e| e == 'b'} # => nil

But this Array#index {block) is acceptable, yes?

Yes, I think that could be useful.
Couldn't the index of a hash be considered the key? So the block of #index
when applied is the value. i.e.

Good idea! That way Hash and Array are partly interchangable. You could
view an array as a special case of an associative storage with the
restriction that keys are ints.
{:a=>'a',:b=>'b',:c=>'b'}.index{|e| e == 'b'} # => :b

But then, of course, there would be no telling which key you might get.
Suppose that could be considered a problem.

The same holds for #index so I think this is not a problem. You only get
one key, presumably the first that is found. Same story for Array#index:
=> 0
=> nil
I see.

Hmm... sometimes it seems like these are quite categorized as finely as
they
might be.

Yes, definitely! That's what I discovered, too, when I suggested
Enumerable#size and Enumerable#empty? They just need more preconditions
than Enumerable. Matz did really a great job here!

Kind regards

robert
 
D

David A. Black

Hi --

Tiny RCR suggestion:

Array#index optionally take a block like Enumerable#detect does.

['a','b','c'].index{|e| e == 'b'} # => 1
['a','b','c'].index{|e| e == 'c'} # => 2
['a','a','a'].index{|e| e == 'a'} # => 0
['a','a','a'].index{|e| e == 'b'} # => nil

See the thread at
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/105314
for a recent discussion of this. I basically like the idea, with a
couple of caveats which are discussed in that thread.


David
 
D

David A. Black

Hi --

Couldn't the index of a hash be considered the key? So the block of #index
when applied is the value. i.e.

That's how I tend to see it, though Ruby has two interpretations of
"index" for hashes:

irb(main):007:0> h = Hash[*%w{a b c d}]
=> {"a"=>"b", "c"=>"d"}
irb(main):008:0> h.index("d")
=> "c"
irb(main):009:0> h.each_with_index {|e,i| p i if e[0] == "c"}
1

This is one of the reasons I've always felt that Hash#each_with_index
should be eliminated. The "index" in h.each_with_index is not the
same as the "index" of h.index. h.each_with_index is effectively
equivalent to h.to_a.each_with_index, but with the to_a being hidden.


David
 
T

trans. (T. Onoma)

Couldn't the index of a hash be considered the key? So the block of
#index when applied is the value. i.e.

That's how I tend to see it, though Ruby has two interpretations of
"index" for hashes:

irb(main):007:0> h = Hash[*%w{a b c d}]
=> {"a"=>"b", "c"=>"d"}
irb(main):008:0> h.index("d")
=> "c"
irb(main):009:0> h.each_with_index {|e,i| p i if e[0] == "c"}
1

This is one of the reasons I've always felt that Hash#each_with_index
should be eliminated. The "index" in h.each_with_index is not the
same as the "index" of h.index. h.each_with_index is effectively
equivalent to h.to_a.each_with_index, but with the to_a being hidden.

Right! Index in this second sense has no significance with regards to Hash
proper.

To be honest I have always felt a bit odd about Hash being "Enumerable" for
this very reason. Hash elements cannot be "numbered" --unless converted
(whether by key or by value) into an array first. Perhaps part of the oddness
is just that the word "Enumerable" cannotes more then it should. "Indexable"
seems more exact.

T.

--
( o _ カラãƒ
// trans.
/ \ (e-mail address removed)

I don't give a damn for a man that can only spell a word one way.
-Mark Twain
 
F

Florian Gross

trans. (T. Onoma) said:
Couldn't the index of a hash be considered the key? So the block of #index
when applied is the value. i.e.

I agree heavily with this. It would greatly simplify Hashes. If we then
could also make them yield(value, key) and merge Enumerable#each and
Enumerable#each_with_index (and propagate that to the other methods like
#map and so on) Enumerables would really only need to provide #each
instead of overwriting all the Hash methods. It would contribute to
consistency and simplicity IMHO, but it is a big change.

Regards,
Florian Gross
 
Y

Yukihiro Matsumoto

Hi,

In message "Re: Array#index block and rdetect"

|> Couldn't the index of a hash be considered the key? So the block of #index
|> when applied is the value. i.e.
|
|Good idea! That way Hash and Array are partly interchangable. You could
|view an array as a special case of an associative storage with the
|restriction that keys are ints.

In that case, Hash#each and Enumerable#each_with_index should be
redefined for consistency.

matz.
 
D

David A. Black

Hi --

Hi,

In message "Re: Array#index block and rdetect"

|> Couldn't the index of a hash be considered the key? So the block of #index
|> when applied is the value. i.e.
|
|Good idea! That way Hash and Array are partly interchangable. You could
|view an array as a special case of an associative storage with the
|restriction that keys are ints.

In that case, Hash#each and Enumerable#each_with_index should be
redefined for consistency.

Could #each_with_index be left to individual classes, as #each_index
is?


David
 
Y

Yukihiro Matsumoto

Hi,

In message "Re: Array#index block and rdetect"

|> In that case, Hash#each and Enumerable#each_with_index should be
|> redefined for consistency.
|
|Could #each_with_index be left to individual classes, as #each_index
|is?

Can you express your idea in detail?

* Enumerable#each_index should be removed (yes/no)
* Array#each_with_index should be added (yes/no)
* Hash#each_with_index should be added with key as index (yes/no)
* How about other enumerable classes?

matz.
 
D

David A. Black

Hi --

Hi,

In message "Re: Array#index block and rdetect"

|> In that case, Hash#each and Enumerable#each_with_index should be
|> redefined for consistency.
|
|Could #each_with_index be left to individual classes, as #each_index
|is?

Can you express your idea in detail?

* Enumerable#each_index should be removed (yes/no)

There is no Enumerable#each_index -- nothing to remove.
* Array#each_with_index should be added (yes/no)

Yes. (Florian's ideas about merging #each and #each_with_index is
also interesting, though I'm not sure it would be good to always have
an "extra" parameter passed to the block.)
* Hash#each_with_index should be added with key as index (yes/no)

No. The key is already available to block, with #each. (But you said
Hash#each would be redefined -- I'm not sure what that would involve.)
* How about other enumerable classes?

I think the idea of every enumerable class having an "index", defined
as part of that class, is possibly useful. For hashes it could be the
keys; for arrays, the integer index; for files, the line number. In
some cases (like index/key for hashes), it might be redundant. But it
might open up some good possibilities.

That would mean an enumerable class would have to be able to say:
"This is how I define 'index'." I'm not sure how that would work.


David
 
Y

Yukihiro Matsumoto

Hi,

In message "Re: Array#index block and rdetect"

|> * Enumerable#each_index should be removed (yes/no)
|
|There is no Enumerable#each_index -- nothing to remove.

I meant each_with_index.

|> * How about other enumerable classes?
|
|I think the idea of every enumerable class having an "index", defined
|as part of that class, is possibly useful. For hashes it could be the
|keys; for arrays, the integer index; for files, the line number. In
|some cases (like index/key for hashes), it might be redundant. But it
|might open up some good possibilities.

The most consistent (but incompatible) change would be:

* leave Enumerable#each_with_index unchanged.
* make Hash#each as alias of Hash#each_value
* redefine Hash#each_with_index as alias of Hash#each_pair

But this change may break many programs.
matz.
 
R

Robert Klemme

Yukihiro Matsumoto said:
Hi,

In message "Re: Array#index block and rdetect"
|> * Enumerable#each_index should be removed (yes/no)
|
|There is no Enumerable#each_index -- nothing to remove.

I meant each_with_index.

|> * How about other enumerable classes?
|
|I think the idea of every enumerable class having an "index", defined
|as part of that class, is possibly useful.

Sorry, David, I stongly disagree: IMHO an index does only make sense in a
class that maintains a certain order (such as Array). A Hash does not
have a particular order and thus Enumerable#each_with_index is the
appropriate thing; here the index is valid just for the current iteration
and can be used for printing or whatever. But I would not want to add an
index to a Hash.

Or did you mean to use the hash key as index? That would be a different
story... While that would make sense for Array and Hash I think there are
a lot Enumerables out there that do not correspond easily to associative
storage, for example a Enumerable that emits arbitrary many random numbers
in its #each method.
For hashes it could be the
|keys; for arrays, the integer index; for files, the line number. In
|some cases (like index/key for hashes), it might be redundant. But it
|might open up some good possibilities.

The most consistent (but incompatible) change would be:

* leave Enumerable#each_with_index unchanged.
* make Hash#each as alias of Hash#each_value
* redefine Hash#each_with_index as alias of Hash#each_pair

But this change may break many programs.

Yeah, that's true. What about a method in Hash that changes method
behavior to the array compatible style? That way no old code is broken
and you can purposely change a Hash's look if you need to make sure that
this Hash can be interchangeably used with an Array.

Kind regards

robert
 
D

David A. Black

Hi --

Yukihiro Matsumoto said:
Hi,

In message "Re: Array#index block and rdetect"


Sorry, David, I stongly disagree: IMHO an index does only make sense in a
class that maintains a certain order (such as Array). A Hash does not
have a particular order and thus Enumerable#each_with_index is the
appropriate thing; here the index is valid just for the current iteration
and can be used for printing or whatever. But I would not want to add an
index to a Hash.

Or did you mean to use the hash key as index?

Yes. I certainly didn't mean numerical indexes for hashes; that's the
whole problem (well, part of the problem) with Hash#each_with_index in
the first place. Also, by "defined as part of that class", I meant
defined according to the needs of that class, so that for arrays it
would be integers, for hashes the keys, etc.
That would be a different
story... While that would make sense for Array and Hash I think there are
a lot Enumerables out there that do not correspond easily to associative
storage, for example a Enumerable that emits arbitrary many random numbers
in its #each method.

That problem is already there, in the sense that such an object
already has an #each_with_index method. I'm trying to make sense of
the notion of "index" as part of Enumerable, though it's quite
possible that *not* having it be part of Enumerable would be better --
and then classes could either define index-related methods or not.
(That's what I meant originally about leaving #each_with_index up to
the individual classes, like #each_index.)
Yeah, that's true. What about a method in Hash that changes method
behavior to the array compatible style? That way no old code is broken
and you can purposely change a Hash's look if you need to make sure that
this Hash can be interchangeably used with an Array.

It's called #to_a :) I think that's better than having a switch that
changes behavior. We're going to start hearing a lot of "for
historical reasons..." and "glued on as an afterthought..." otherwise
:)


David
 
D

David A. Black

Hi --

Hi,

In message "Re: Array#index block and rdetect"

|> * Enumerable#each_index should be removed (yes/no)
|
|There is no Enumerable#each_index -- nothing to remove.

I meant each_with_index.

In that case, yes.
|> * How about other enumerable classes?
|
|I think the idea of every enumerable class having an "index", defined
|as part of that class, is possibly useful. For hashes it could be the
|keys; for arrays, the integer index; for files, the line number. In
|some cases (like index/key for hashes), it might be redundant. But it
|might open up some good possibilities.

The most consistent (but incompatible) change would be:

* leave Enumerable#each_with_index unchanged.

Question: if "index" is a basic Enumerable thing, why is there no
Enumerable#each_index? (My preference would be to push
#each_with_index down to the individual classes too; but in any case,
I'm curious about it.)
* make Hash#each as alias of Hash#each_value
* redefine Hash#each_with_index as alias of Hash#each_pair

Actually it might be better to have Hash#each_with_index yield (value,
key) (like Florian's idea), since the value is the element and the key
is the index. However, calling it "index" instead of "key" then just
becomes arbitrary, and has a "legacy" feel to it.
But this change may break many programs.

The #each change might, but I don't think I've ever seen anyone use
Hash#each_with_index so that probably wouldn't matter.


David
 
R

Robert Klemme

David A. Black said:
Hi --

Yes. I certainly didn't mean numerical indexes for hashes; that's the
whole problem (well, part of the problem) with Hash#each_with_index in
the first place. Also, by "defined as part of that class", I meant
defined according to the needs of that class, so that for arrays it
would be integers, for hashes the keys, etc.

Ok, I see. I wouldn't change the behavior of #each_with_index since that
is likely to break a lot code. Read on for my suggestion.
That problem is already there, in the sense that such an object
already has an #each_with_index method. I'm trying to make sense of
the notion of "index" as part of Enumerable, though it's quite
possible that *not* having it be part of Enumerable would be better --
and then classes could either define index-related methods or not.
(That's what I meant originally about leaving #each_with_index up to
the individual classes, like #each_index.)

Well, I think the main problem here is confusion of two different things:
numerical indexing (I'll use the term "index" for this) and lookup keys
(called "keys" hereafter).

In my understanding Enumerable#each_with_index just goes through the
enumerable and counts an index which can be used for printing or counting
or whatever. So I would not change this method. These indexes are purely
per enumeration and can change for any number of reasons.

Additionally we should have Array#each_with_key and Hash#each_with_key and
AnyOtherLookupCollection#each_with_key (or call it #each_pair) that yield
key, value pairs. In the case of an Array the keys happen to be identical
with the indexes of a forward iteration but in case of a Hash keys are
hash keys and thus different from indexes.

I think the problem stems from the fact that we want to handle indexes and
keys with a single set of methods wile in fact these are different things
that only occasionally overlap.
It's called #to_a :) I think that's better than having a switch that
changes behavior. We're going to start hearing a lot of "for
historical reasons..." and "glued on as an afterthought..." otherwise
:)

Yeah, you're right.

Kind regards

robert
 
D

David A. Black

Hi --

Ok, I see. I wouldn't change the behavior of #each_with_index since that
is likely to break a lot code. Read on for my suggestion.

I honestly doubt it would break much code. I have never seen
Hash#each_with_index used.
Well, I think the main problem here is confusion of two different things:
numerical indexing (I'll use the term "index" for this) and lookup keys
(called "keys" hereafter).

In my understanding Enumerable#each_with_index just goes through the
enumerable and counts an index which can be used for printing or counting
or whatever. So I would not change this method. These indexes are purely
per enumeration and can change for any number of reasons.

I have the same understanding, and that's why I *would* change this
(frequently useless) method :) See below....
Additionally we should have Array#each_with_key and Hash#each_with_key and
AnyOtherLookupCollection#each_with_key (or call it #each_pair) that yield
key, value pairs. In the case of an Array the keys happen to be identical
with the indexes of a forward iteration but in case of a Hash keys are
hash keys and thus different from indexes.

I think the problem stems from the fact that we want to handle indexes and
keys with a single set of methods wile in fact these are different things
that only occasionally overlap.

Actually my suggestion earlier was to detach the concept of "index"
from Enumerable so that each enumerable class could define it as it
wanted to. That's why I'd like to push #each_with_index out of
Enumerable. It's the only "index" method in Enumerable, and I think
it can lead to too specific a concept of indexing for classes like
Hash where numerical indexes are essentially meaningless. (I guess
this might change if hashes become ordered....)

I would prefer, in other words, for key and index to overlap in Hashes
as well as Arrays. I just don't see enough advantage in having this
semi-magic #each_with_index at the level of Enumerable (semi-magic in
the sense that it does a kind of implicit to_a).

Or, if index always means a (to_a-based) numerical index, then
#each_index should be in Enumerable, and not left to the individual
classes. Then it would be clearer that index == 0-origin, possibly
meaningless (for unordered collections), numerical index. Classes
that specialized from this could either re-use the name index (for
example, a 1-origin collection), or introduce a set of methods with a
new name/concept (like key).


David
 
F

Florian Gross

Robert said:
Well, I think the main problem here is confusion of two different things:
numerical indexing (I'll use the term "index" for this) and lookup keys
(called "keys" hereafter).

Let me propose yet another alternative. (More general than my last one.)
Let .each yield(item, *more) and make all methods provided by Enumerable
pass on *more.

This would allow Hash#each to do this:

class Hash
def each
loop over key => value pairs do
yield(value, key)
end
end

include Enumerable
end

hash = {1 => 2, 3 => 4}
hash.each { |value,| puts value }
hash.map { |value, key| [key, value] } # from hash to assoc array
hash.inject(0) { |state, value, key| state + [value, key].hash }

and Array to do this:

class Array
def each
0.upto(size - 1) do |index|
yield(self[index], index)
end
end

include Enumerable
end

array = ["hello", "nice", "world"]
array.find_all { |item, index| index > 0 }
array.each { |item,| p item }

I still dislike the trailing comma that is needed if you don't want to
use the extra information. This could be fixed by doing an arity check
on blocks and not yielding the extra information when the block only
wants a single argument.

Also note that this means we won't have to deal with all the
#map_with_index and so on trouble any more, Hash wouldn't need to
virtually overwrite any method provided by Enumerable and that we can
even easily make Enumerables that yield other information. (Is anybody
able to think about a good use for that feature?)

The biggest problem is that backwards compatibility would be severely
broken if this were to be introduced. Maybe even too severely for Rite.
Kind regards
robert

More regards,
Florian Gross
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,127
Latest member
CyberDefense
Top