Issue #16270 has been updated by jeremyevans0 (Jeremy Evans).

Status changed from Open to Closed

You need to look at the functions passed to `rb_hash_foreach`:

```c
static int
each_pair_i(VALUE key, VALUE value, VALUE _)
{
    rb_yield(rb_assoc_new(key, value));
    return ST_CONTINUE;
}

static int
select_i(VALUE key, VALUE value, VALUE result)
{
    if (RTEST(rb_yield_values(2, key, value))) {
        rb_hash_aset(result, key, value);
    }
    return ST_CONTINUE;
}
```

`each_pair_i` yields a single array argument with the key and the value, `select_i` yields 2 arguments (key and value separately).

This is inconsistent, and could potentially be changed so that blocks passed to `Hash#select` that accept a single argument are yielded an array.  However, that may cause backwards compatibility issues with existing code that expects the key to be yielded to the block (instead of an array with the key and value).

I don't think the current behavior is a bug, so I'm going to close this.  If you would like `Hash#select` behavior changed when passing a block that accepts a single argument, please submit a feature request for that.

----------------------------------------
Bug #16270: Strange behavior on Hash's #each and #select method.
https://bugs.ruby-lang.org/issues/16270#change-82237

* Author: zw963 (Wei Zheng)
* Status: Closed
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: 2.6.3
* Backport: 2.5: UNKNOWN, 2.6: UNKNOWN
----------------------------------------
Following is some example code:

``` ruby
sample_hash = {
    "246" => {
        "price" => "8000",
         "note" => ""
    },
    "247" => {
        "price" => "8000",
         "note" => ""
    },
    "248" => {
        "price" => "8000",
         "note" => ""
    }
}

sample_hash.each {|e| p e}
# following is p output content, we can see e is a hash element, and convert to a array object.
# this is expected behavior maybe, anyway, hash is same as a nested array.
["246", {"price"=>"8000", "note"=>""}]
["247", {"price"=>"8000", "note"=>""}]
["248", {"price"=>"8000", "note"=>""}]

sample_hash.select {|e| p e }
# Wired, why this time, e output different with each?
"246"
"247"
"248"
```

Following is source code for **each**

```c
static VALUE
rb_hash_each_pair(VALUE hash)
{
    RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
    if (rb_block_arity() > 1)
        rb_hash_foreach(hash, each_pair_i_fast, 0);
    else
        rb_hash_foreach(hash, each_pair_i, 0);
    return hash;
}
```

Following is source code for **select**

```c
VALUE
rb_hash_select(VALUE hash)
{
    VALUE result;

    RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
    result = rb_hash_new();
    if (!RHASH_EMPTY_P(hash)) {
        rb_hash_foreach(hash, select_i, result);
    }
    return result;
}
```

I don't  understand C well, don't know why lack of consistency for above two Hash method,
but, i think it is a little confuse me.

Thank you.






-- 
https://bugs.ruby-lang.org/

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