سؤال

Suppose I create the following arrays in ruby:

a = ["apple", "cherry"]
b = a.dup

Here, b is a shallow copy of a. So if I do:

a.each{|fruit| fruit << " pie"}

I get both a and b equal to ["apple pie", "cherry pie"]. No problem there. But suppose I change one element of b:

b[1] = "blueberry"

and issue the same "each" command. Now b is ["apple pie", "blueberry"], because a[0] and b[0] are the same strings, but a[1] and b[1] are different strings. I could run the command on both a and b, but then b is ["apple pie pie", "blueberry pie"], because I have run the append operation on the same string twice.

Is there a way to modify in place all the strings of a and b, without duplicates. In this simple example, I could test for the substring " pie", but this wouldn't work for other types of changes (such as deleting the first character).

I tried creating a set containing all the strings, so that each would be unique; but it seems the set creation copies the strings, so they cannot be modified in place. Is there a way to test if two strings are the same in memory? I have googled for that, but found nothing.

The application of this is that I have big arrays of strings, which I "dup" to create a history of them. Now I want to apply a change to the entire history, without double applying (or triple, etc) the changes.

هل كانت مفيدة؟

المحلول

I don't understand your use case; I suspect you're making things more complicated than they need to be.

Is there a way to test if two strings are the same in memory?

Object#object_id is what you're looking for.

Is there a way to modify in place all the strings of a and b, without duplicates?

You could keep a set of not all the object_ids, similar to what you were already trying. You can retrieve the string with ObjectSpace#_id2ref. Something like this:

require 'set'

set = Set.new
a = ["apple", "cherry"]
b = a.dup
b[1] = "blueberry"

# Collect unique string objects
a.each{|s| set << s.object_id}
b.each{|s| set << s.object_id}

# Make pie with each unique string object
set.each{|id| ObjectSpace._id2ref(id) << " pie"}

a
# => ["apple pie", "cherry pie"]
b
# => ["apple pie", "blueberry pie"]

That seems a bit crazy to me, though. Again, I think there's probably a better way to do what you're trying to do, but it's hard to tell based on the information provided.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top