我有以下对象数组
{
: items=>[
{
: id=>"cam-id-1",
: translations=>[
{
: name=>"abcd",
: description=>"geiajfe",
: locale=>: fr,
: createdAt=>Fri,
27Jul201800: 00: 00UTC+00: 00,
: updatedAt=>Fri,
27Jul201800: 00: 00UTC+00: 00
},
{
: name=>"bon jor",
: description=>"jwi nifneaoin ofieafi",
: locale=>: de,
: createdAt=>Fri,
27Jul201800: 00: 00UTC+00: 00,
: updatedAt=>Fri,
27Jul201800: 00: 00UTC+00: 00
},
{
: name=>"hello",
: description=>"hello abcd",
: locale=>: en,
: createdAt=>Fri,
27Jul201800: 00: 00UTC+00: 00,
: updatedAt=>Fri,
27Jul201800: 00: 00UTC+00: 00
}
]
},
{
: id=>"cam-id-2",
: translations=>[
]
}
],
}
我想根据语言环境过滤翻译数组。因此,例如,如果我通过locale = fr,则返回整个对象,但在翻译中仅返回一个对象,因为只有一个语言环境fr。
所以输出将是
{
: items=>[
{
: id=>"cam-id-1",
: translations=>[
{
: name=>"abcd",
: description=>"geiajfe",
: locale=>: fr,
: createdAt=>Fri,
27Jul201800: 00: 00UTC+00: 00,
: updatedAt=>Fri,
27Jul201800: 00: 00UTC+00: 00
}
]
},
{
: id=>"cam-id-2",
: translations=>[
]
}
],
}
我创建了一种过滤翻译的方法,但它只返回过滤后的翻译,我认为这不是正确的方法。
def filter_translations(test)
array = []
test[:items][0][:translations].each do |t|
array << t if t[:locale].to_s.casecmp(locale.to_s).zero? || t[:locale].to_s.include?(locale.to_s)
end
array
end
有什么主意吗?
答案 0 :(得分:0)
要从列表中仅获取单个内容,请使用first
。
# {:name=>"abcd", :description=>"geiajfe", :locale=>:fr}
translation_fr = item.fetch(:translations).first { |translation|
translation[:locale] == :fr
}
要获取所有项目的内容,请将其包装在map
中。
# [ {:name=>"abcd", :description=>"geiajfe", :locale=>:fr}, ... ]
items_fr = test.fetch(:items).map { |item|
item.fetch(:translations).first { |translation|
translation[:locale] == :fr
}
}
要返回项目+所选的翻译,您可以从map
返回。但是您需要注意,item
不是副本。如果您在map
中进行了更改,则在tests
中进行了更改。
例如...
items_fr = test.fetch(:items).map { |item|
translation = item.fetch(:translations).first { |translation|
translation[:locale] == :fr
}
item[:translations] = [translation]
item
}
这将返回您想要的。
{:id=>"cam-id-1", :translations=>[{:name=>"abcd", :description=>"geiajfe", :locale=>:fr}]}
但是它也会更改test
中的项目,因为它们是相同的对象。相反,您需要返回每个item
的副本。您可以呼叫item = item.clone
并更改密钥,也可以一步一步使用merge
。
items_fr = test.fetch(:items).map { |item|
translation = item.fetch(:translations).first { |translation|
translation[:locale] == :fr
}
item.merge translations: [translation]
}
建议您不要为选定的翻译添加新的item[:translations]
键,而不是更改translation
。
# [ {:id=>"cam-id-1", :translations=>[{:name=>"abcd", :description=>"geiajfe", :locale=>:fr}, {:name=>"bon jor", :description=>"jwi nifneaoin ofieafi", :locale=>:de}, {:name=>"hello", :description=>"hello abcd", :locale=>:en}], :translation=>{:name=>"abcd", :description=>"geiajfe", :locale=>:fr}} ]
items_fr = test.fetch(:items).map { |item|
translation = item.fetch(:translations).first { |translation|
translation[:locale] == :fr
}
item[:translation] = translation
item
}
现在,如果需要,您可以重复此过程以选择新的翻译。
您可以通过几种方式改进此过程。首先,如果可能,请将translation
数组更改为在语言环境上键入的哈希值,以加快查找速度。其次,将所有内容放入封装细节的对象中,并允许更复杂的行为。
class Translations
attr_accessor :translations
def initialize
@translations = {}
end
# Get the translation for a locale
def for_locale(locale)
translations.fetch(locale)
end
# Add a translation for a locale
def add_translation(translation)
translations[translation.locale] = translation
end
# Import translations from an array. Reorganize
# them as a hash keyed on locale.
def import_from_array(translations)
translations.each do |import_translation|
add_translation Translation.new(import_translation)
end
end
end
class Translation
attr_accessor :name, :description, :locale
def initialize(name:, description:, locale:)
@name = name
@description = description
@locale = locale
end
end
class Item
attr_accessor :translations, :translation, :id
def initialize
@translations ||= Translations.new
end
def pick_translation(locale)
@translation = translations.for_locale(locale)
end
def import_from_hash(**args)
@id = args.fetch(:id)
translations.import_from_array( args.fetch(:translations) )
end
end
items = test.fetch(:items).map do |import|
# parse
item = Item.new.import_from_hash(import)
# pick a translation
item.pick_translation(:fr)
# return the object
item
end
例如,如果重复这些翻译并且副本占用了内存,则可以利用Flyweight pattern。他们可以共享相同的Translation对象,而不是每个Item都有自己的副本。
我使用的是Hash#fetch
而不是[]
,因此如果缺少必需的键,它将抛出KeyError
异常。