Hi,
At Mon, 25 Apr 2005 16:36:21 +0900,
Daniel Amelang wrote in [ruby-talk:139707]:
So why not go back to David's suggestion of adding a delete_at method
for the case of multiple values? And have it _always_ return an array.
Because Array already has delete_at which takes just one
argument. It feels similar enough to cause confusion, doesn't
it?
Index: hash.c
===================================================================
RCS file: /cvs/ruby/src/ruby/hash.c,v
retrieving revision 1.148
diff -U2 -p -u -r1.148 hash.c
--- hash.c 2 Apr 2005 04:23:56 -0000 1.148
+++ hash.c 25 Apr 2005 09:34:45 -0000
@@ -625,9 +625,8 @@ rb_hash_index(hash, value)
* hsh.delete(key) {| key | block } => value
*
- * Deletes and returns a key-value pair from <i>hsh</i> whose key is
- * equal to <i>key</i>. If the key is not found, returns the
- * <em>default value</em>. If the optional code block is given and the
- * key is not found, pass in the key and return the result of
- * <i>block</i>.
+ * Deletes and returns a value from <i>hsh</i> whose key is equal to
+ * <i>key</i>. If the key is not found, returns the +nil+. If the
+ * optional code block is given and the key is not found, pass in the
+ * key and return the result of <i>block</i>.
*
* h = { "a" => 100, "b" => 200 }
@@ -659,4 +658,88 @@ rb_hash_delete(hash, key)
}
+/*
+ * call-seq:
+ * hsh.remove!(key1, ...) => [value1, ...]
+ * hsh.remove!(key1, ...) {| key | block } => [value1, ...]
+ *
+ * Deletes and returns a value from <i>hsh</i> whose key is equal to
+ * <i>key</i>. If the key is not found, returns the +nil+. If the
+ * optional code block is given and the key is not found, pass in the
+ * key and return the result of <i>block</i>.
+ *
+ * h = { "a" => 100, "b" => 200 }
+ * h.remove!("a", "b") #=> [100, 200]
+ * h = { "a" => 100, "b" => 200 }
+ * h.remove!("z", "a") #=> [nil, 100]
+ * h.remove!("z") { |el| "#{el} not found" } #=> "z not found"
+ *
+ */
+
+VALUE
+rb_hash_remove_bang(argc, argv, hash)
+ int argc;
+ VALUE *argv;
+ VALUE hash;
+{
+ int i;
+ VALUE ret = rb_ary_new2(argc);
+
+ rb_hash_modify(hash);
+ for (i = 0; i < argc; ++i) {
+ st_data_t key = (st_data_t)argv
, val;
+ if (RHASH(hash)->iter_lev > 0) {
+ if (st_delete_safe(RHASH(hash)->tbl, &key, &val, Qundef)) {
+ FL_SET(hash, HASH_DELETED);
+ rb_ary_push(ret, (VALUE)val);
+ continue;
+ }
+ }
+ else if (st_delete(RHASH(hash)->tbl, &key, &val)) {
+ rb_ary_push(ret, (VALUE)val);
+ continue;
+ }
+ if (rb_block_given_p()) {
+ rb_ary_push(ret, rb_yield((VALUE)key));
+ }
+ }
+ return ret;
+}
+
+/*
+ * call-seq:
+ * hsh.remove(key1, ...) => newhsh
+ * hsh.remove(key1, ...) {| key | block } => newhsh
+ *
+ * Returns a copy of <i>hsh</i> which doesn't contain pairs whose key
+ * is equal to any given <i>key</i>s. If the optional code block is
+ * given and the key is not found, pass in the key.
+ *
+ * h = { "a" => 100, "b" => 200 }
+ * h.remove!("a", "b") #=> [100, 200]
+ * h = { "a" => 100, "b" => 200 }
+ * h.remove!("z", "a") #=> [nil, 100]
+ * h.remove!("z") { |el| "#{el} not found" } #=> "z not found"
+ *
+ */
+
+VALUE
+rb_hash_remove(argc, argv, hash)
+ int argc;
+ VALUE *argv;
+ VALUE hash;
+{
+ int i;
+
+ hash = rb_obj_dup(hash);
+ for (i = 0; i < argc; ++i) {
+ st_data_t key = (st_data_t)argv, val;
+ if (!st_delete(RHASH(hash)->tbl, &key, &val) &&
+ rb_block_given_p()) {
+ rb_yield((VALUE)key);
+ }
+ }
+ return hash;
+}
+
struct shift_var {
int stop;
@@ -2527,4 +2610,6 @@ Init_Hash()
rb_define_method(rb_cHash,"reject", rb_hash_reject, 0);
rb_define_method(rb_cHash,"reject!", rb_hash_reject_bang, 0);
+ rb_define_method(rb_cHash,"remove!", rb_hash_remove_bang, -1);
+ rb_define_method(rb_cHash,"remove", rb_hash_remove, -1);
rb_define_method(rb_cHash,"clear", rb_hash_clear, 0);
rb_define_method(rb_cHash,"invert", rb_hash_invert, 0);