Reputation: 42207
I use in a genealogy program following method to add a mariage/spouse to a Person. @mariages is an array of arrays.
def add_spouse(spouse, mariage_date = nil, divorce_date = nil)
@mariages.push([spouse, mariage_date, divorce_date]) unless @mariages.index{|(a, b, c)| a == spouse && b == mariage_date}
spouse.mariages.push(self) unless spouse.mariages.index{|(a, b, c)| a == self && b == mariage_date}
end
With the unless @mariages.index{|(a, b, c)| a == spouse && b == mariage_date}
i check if the mariage is not allready in the array.
Now i want to keep my mariages in an array of hashes like this
def add_spouse(spouse, mariage_date = nil, divorce_date = nil)
@mariages.push({:spouse => spouse, :mariage_date => mariage_date, :divorce_date => divorce_date}) unless ...
spouse.mariages.push({:spouse => self, :mariage_date => mariage_date, :divorce_date => divorce_date}) unless ...
end
Can someone help me adapt the unless part to do the check if the hash is not allready presant in the array ?
Upvotes: 0
Views: 78
Reputation: 27232
As per your question in the commend I'd do something like the following. Note that Dates should use the date class and the partners in the marriage should be classes too, with births and deaths and whatnot. But hopefully you can see how moving the data into objects that know what to do with it, can simplify the design as things get larger. (I also went with bride and groom for simplicity, feel free to change that in a genealogically approved manner).
Each person would have a Marriages associated with them and if you had a bride and a groom they could share a single Marriage, but have a different list of Marriages.
class Marriage
attr_accessor :marriage_date, :divorce_date, :bride, :groom
def initialize(date, bride, groom)
@marriage_date = date
@bride = bride
@groom = groom
end
def marriage_equals(m)
return (@marriage_date == m.marriage_date) &&
(@bride == m.bride) &&
(@groom == m.groom)
end
end
class Marriages
def initialize
@marriages = []
end
def add_marriage(marriage)
if (@marriages.any? { |m| m.marriage_equals(marriage) })
puts "Marriage of #{marriage.groom} already listed"
return false
else
puts "Added new marriage"
@marriages.push(marriage)
return true
end
end
end
m1 = Marriage.new("1-1-0002", "Wilma", "Fred")
m2 = Marriage.new("6-8-0003", "Betty", "Barney")
m3 = Marriage.new("2-8-8003", "Jane", "George")
marriages = [m1,m2]
p marriages.any? { |m| m.marriage_equals(m1) } # true
p marriages.any? { |m| m.marriage_equals(m3) } # false
m_list = Marriages.new
m_list.add_marriage(m1) # Added new marriage
m_list.add_marriage(m2) # Added new marriage
m_list.add_marriage(m2) # Marriage of Barney already listed
Upvotes: 1
Reputation: 31087
In the block that goes into index
the element getting iterated over is a hash so you should use
.. unless @mariages.index{|h| h[:spouse] == spouse && h[:mariage_date] == mariage_date}
and
.. unless spouse.mariages.index{|h| h[:spouse] == self && h[:mariage_date] == mariage_date}
PS: mariage
is misspelled. It should be marriage.
Upvotes: 1
Reputation: 230411
Since your array now contains hashes instead of other arrays, you can't use "array unpacking" (not sure what's the official term for that is). You will get an instance of hash, and you can access it as you normally would.
@mariages.push({:spouse => spouse,
:mariage_date => mariage_date,
:divorce_date => divorce_date}) unless @mariages.index{|h| h[:spouse] == spouse && h[:mariage_date] == mariage_date}
Upvotes: 1