Creating a Data Model for nested JSON parameters - ios

I am working with the Spotify API and having trouble with the data model due to the JSON data being more complex than any other data I've seen via tutorials or courses. How would I make my struct for the "items" in this JSON data? I understand a majority of the parameters, for example, "album_group": String and "available_markets": [String] but I don't understand what to do with "artists", "external_urls", and "images". Any help would be appreciated.
Below is the first "item" from the data.
Side Note When I'm creating my struct do I have to include EVERY parameter shown below for my API call to work?
{
"href": "https://api.spotify.com/v1/artists/3qiHUAX7zY4Qnjx8TNUzVx/albums?offset=0&limit=20&include_groups=album,single,compilation,appears_on&locale=en-US,en;q=0.9",
"items": [
{
"album_group": "album",
"album_type": "album",
"artists": [
{
"external_urls": {
"spotify": "https://open.spotify.com/artist/3qiHUAX7zY4Qnjx8TNUzVx"
},
"href": "https://api.spotify.com/v1/artists/3qiHUAX7zY4Qnjx8TNUzVx",
"id": "3qiHUAX7zY4Qnjx8TNUzVx",
"name": "Yeat",
"type": "artist",
"uri": "spotify:artist:3qiHUAX7zY4Qnjx8TNUzVx"
}
],
"available_markets": [
"AD",
"AE",
"AG",
"AL",
"AM",
"AO",
"AR",
"AT",
"AU",
"AZ",
"BA",
"BB",
"BD",
"BE",
"BF",
"BG",
"BH",
"BI",
"BJ",
"BN",
"BO",
"BR",
"BS",
"BT",
"BW",
"BY",
"BZ",
"CA",
"CD",
"CG",
"CH",
"CI",
"CL",
"CM",
"CO",
"CR",
"CV",
"CY",
"CZ",
"DE",
"DJ",
"DK",
"DM",
"DO",
"DZ",
"EC",
"EE",
"EG",
"ES",
"FI",
"FJ",
"FM",
"FR",
"GA",
"GB",
"GD",
"GE",
"GH",
"GM",
"GN",
"GQ",
"GR",
"GT",
"GW",
"GY",
"HK",
"HN",
"HR",
"HT",
"HU",
"ID",
"IE",
"IL",
"IN",
"IQ",
"IS",
"IT",
"JM",
"JO",
"JP",
"KE",
"KG",
"KH",
"KI",
"KM",
"KN",
"KR",
"KW",
"KZ",
"LA",
"LB",
"LC",
"LI",
"LK",
"LR",
"LS",
"LT",
"LU",
"LV",
"LY",
"MA",
"MC",
"MD",
"ME",
"MG",
"MH",
"MK",
"ML",
"MN",
"MO",
"MR",
"MT",
"MU",
"MV",
"MW",
"MX",
"MY",
"MZ",
"NA",
"NE",
"NG",
"NI",
"NL",
"NO",
"NP",
"NR",
"NZ",
"OM",
"PA",
"PE",
"PG",
"PH",
"PK",
"PL",
"PS",
"PT",
"PW",
"PY",
"QA",
"RO",
"RS",
"RU",
"RW",
"SA",
"SB",
"SC",
"SE",
"SG",
"SI",
"SK",
"SL",
"SM",
"SN",
"SR",
"ST",
"SV",
"SZ",
"TD",
"TG",
"TH",
"TJ",
"TL",
"TN",
"TO",
"TR",
"TT",
"TV",
"TW",
"TZ",
"UA",
"UG",
"US",
"UY",
"UZ",
"VC",
"VE",
"VN",
"VU",
"WS",
"XK",
"ZA",
"ZM",
"ZW"
],
"external_urls": {
"spotify": "https://open.spotify.com/album/1x55Z0fYARLdeJVjG2UESs"
},
"href": "https://api.spotify.com/v1/albums/1x55Z0fYARLdeJVjG2UESs",
"id": "1x55Z0fYARLdeJVjG2UESs",
"images": [
{
"height": 640,
"url": "https://i.scdn.co/image/ab67616d0000b273b20fdc3ee4c262693cfdf005",
"width": 640
},
{
"height": 300,
"url": "https://i.scdn.co/image/ab67616d00001e02b20fdc3ee4c262693cfdf005",
"width": 300
},
{
"height": 64,
"url": "https://i.scdn.co/image/ab67616d00004851b20fdc3ee4c262693cfdf005",
"width": 64
}
],
"name": "Up 2 Më",
"release_date": "2021-09-10",
"release_date_precision": "day",
"total_tracks": 22,
"type": "album",
"uri": "spotify:album:1x55Z0fYARLdeJVjG2UESs"
}
]
}

Good rule of thumb is, that you need a separate Decodable object for every JSON object (marked with {}) when working with such API.
You can nest Decodable structs. Just don't forget that here, ExternalUrl has to be Decodable too, otherwise you will get an error
struct SpotifyItem: Decodable {
// ...
let artists: [Artist]
let images: [SpotifyImage]
// ...
}
struct Artist: Decodable {
let external_urls: ExternalUrl
let href: String
let id: String
// ...
}
struct ExternalUrl: Decodable {
let spotify: String
}
struct SpotifyImage: Decodable {
let url: String
let height: Int
let width: Int
}
Side Note Answer: I would advise you to do so. It seems like there are ways to decode JSON elements into swift dictionary, but it goes against the type safety that you are trying to achieve. You are parsing JSON into Decodable structs precisely because you want to know ahead of time what are you dealing with.
Don't forget you can still do optional attributes, for example you could have
struct ExternalUrl: Decodable {
let spotify: String
let instagram: String?
}
In that case, if instagram is not present, it will be set to nil. My advice would be follow this more modern and safe way of doing things. You can of course parse the entire JSON into a huge [String: Any] object, but you will have to write out everything you want to access anyway. Plus there will be a LOT of type casting and checks, which Codable does for you.

Related

how can i do For Loop Properly

I want to add " 5 " in my arrays in every 3rd position
var myList: [String] = ["U.S", "Spain", "China", "Brazil", "India" , "Canada", "Germany", "UK", "Dubai", "Russia", "Japan", "Italy", "France", "Australia", "Thailand", "Mexico"]
var i = 0
for name in 0...myList.count {
i = i + 1
if i % 3 == 0 {
myList.insert("\(5)", at: i )
}
}
print("\(myList)")
OutPut is:
["U.S", "Spain", "China", "5", "Brazil", "India", "5", "Canada", "Germany", "5", "UK", "Dubai", "5", "Russia", "Japan", "5", "Italy", "France", "Australia", "Thailand", "Mexico"]
but after 16 position in array , I am not able to put all 5 in my arrays because of arrays that is myList have total 16 counts ....so how I can able to put 5 in my Arrays properly
The problem there is that you are mutating the array (changing its elements while iterating it), so what you actually need to do is to insert your elements in reverse order. Try like this:
var myList = ["U.S", "Spain", "China", "Brazil", "India", "Canada", "Germany", "UK", "Dubai", "Russia", "Japan", "Italy", "France", "Australia", "Thailand", "Mexico" ]
for index in myList.indices.dropFirst().reversed() where index % 3 == 0 {
myList.insert("5", at: index)
}
print(myList) // "["U.S", "Spain", "China", "5", "Brazil", "India", "Canada", "5", "Germany", "UK", "Dubai", "5", "Russia", "Japan", "Italy", "5", "France", "Australia", "Thailand", "5", "Mexico"]\n"

Creating an array of numbers to use in a pickerview not working

I have a pickerview tied to a textbox that i'm trying to fill with a range of numbers, 48-96. I don't want to type them all out so i'm using the below:
var height = Array(48...96)
but i get the below error:
Cannot convert return expression of type 'Int' to return type 'String?'
I've tried the below but it doesn't work so i'm helping you kind folks could help:
var height = String(Array(48...96))
I expect to be able to use an array and convert it to a string versus having to type our 48, 49, 50...96 but cant figure out how to convert the array of ints to strings.
You want an array of String containing "48" through "96". You can do that by using map on a range:
var height = (48...96).map(String.init)
print(height)
["48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96"]

Codable/ Decodable is not decoding

Can someone help me out here? I am using Playground for this example, so you can put the whole code into your Playground and see the results.
I found out that when I remove this line:
"address_format": "{{recipient}}\n{{street}}\n{{postalcode}} {{city}}\n{{country}}",
it seems to work.
(The JSON is validated)
import UIKit
struct Country : Decodable {
enum CodingKeys: String, CodingKey {
case continent
case alpha2
case name
}
var name : String?
var continent : String?
var alpha2 : String?
}
let json = """
[
{
"continent": "Europe",
"alpha2": "AD",
"alpha3": "AND",
"country_code": "376",
"currency": "EUR",
"international_prefix": "00",
"ioc": "AND",
"latitude": "42 30 N",
"longitude": "1 30 E",
"name": "Andorra",
"names": [
"Andorre",
"Andorra",
"アンドラ"],
"translations": {
"en": "Andorre",
"it": "Andorra",
"de": "Andorra",
"fr": "Andorre",
"es": null,
"ja": "アンドラ",
"nl": "Andorra",
"ru": "Андорра"},
"national_destination_code_lengths": [2],
"national_number_lengths": [6,7,8,9],
"national_prefix": "None",
"number": "020",
"region": "Europe",
"subregion": "Southern Europe",
"un_locode": "AD",
"languages": ["ca"],
"nationality": "Andorran"},
{
"continent": "Asia",
"address_format": "{{recipient}}\n{{street}}\n{{postalcode}} {{city}}\n{{country}}",
"alpha2": "AE",
"alpha3": "ARE",
"country_code": "971",
"currency": "AED",
"international_prefix": "00",
"ioc": "UAE",
"latitude": "24 00 N",
"longitude": "54 00 E",
"name": "United Arab Emirates",
"names": [
"United Arab Emirates",
"Vereinigte Arabische Emirate",
"Émirats Arabes Unis",
"Emiratos Árabes Unidos",
"アラブ首長国連邦",
"Verenigde Arabische Emiraten"],
"translations": {
"en": "United Arab Emirates",
"it": "Emirati Arabi Uniti",
"de": "Vereinigte Arabische Emirate",
"fr": "Émirats Arabes Unis",
"es": "Emiratos Árabes Unidos",
"ja": "アラブ首長国連邦",
"nl": "Verenigde Arabische Emiraten",
"ru": "Объединенные Арабские Эмираты"},
"national_destination_code_lengths": [2],
"national_number_lengths": [7,8,9],
"national_prefix": "0",
"number": "784",
"region": "Asia",
"subregion": "Western Asia",
"un_locode": "AE",
"languages": ["ar"],
"nationality": "Emirian"}
]
""".data(using: .utf8)!
let decoder = JSONDecoder()
do {
let countries = try decoder.decode([Country].self, from: json)
print(countries)
} catch {
print("erro")
}
If you would print the actually error information
"Unescaped control character around character 722."
rather than meaningless literal string "erro"
the solution is obvious:
The linefeed characters \n must be escaped:
"address_format": "{{recipient}}\\n{{street}}\\n{{postalcode}} {{city}}\\n{{country}}",
You can fix the issue with
let json = """
[
...
]
""".replacingOccurrences(of: "}\n{", with: "}\\n{").data(using: .utf8)!

How to create customer & items in quickbook through api in rails?

I want to create invoice in my Quickbooks account through API from my rails application, but it requires to add customer and item before creating invoice. But I can't get the idea how to add customer and items through API. Can you suggest me???
Thanks.
Start here:
https://developer.intuit.com/
Follow the docs (https://developer.intuit.com/docs/0100_accounting) and implement OAuth to connect to QuickBooks Online.
Create customers by HTTP POSTing a JSON request to QuickBooks Online:
https://developer.intuit.com/docs/api/accounting/Customer
The JSON request will look something like this:
{
"BillAddr": {
"Line1": "123 Main Street",
"City": "Mountain View",
"Country": "USA",
"CountrySubDivisionCode": "CA",
"PostalCode": "94042"
},
"Notes": "Here are other details.",
"Title": "Mr",
"GivenName": "James",
"MiddleName": "B",
"FamilyName": "King",
"Suffix": "Jr",
"FullyQualifiedName": "King Groceries",
"CompanyName": "King Groceries",
"DisplayName": "King's Groceries",
"PrimaryPhone": {
"FreeFormNumber": "(555) 555-5555"
},
"PrimaryEmailAddr": {
"Address": "jdrew#myemail.com"
}
}
You'll get back something like this:
{
"Customer": {
"Taxable": true,
"BillAddr": {
"Id": "112",
"Line1": "123 Main Street",
"City": "Mountain View",
"Country": "USA",
"CountrySubDivisionCode": "CA",
"PostalCode": "94042"
},
"Notes": "Here are other details.",
"Job": false,
"BillWithParent": false,
"Balance": 0,
"BalanceWithJobs": 0,
"CurrencyRef": {
"value": "USD",
"name": "United States Dollar"
},
"PreferredDeliveryMethod": "Print",
"domain": "QBO",
"sparse": false,
"Id": "67",
"SyncToken": "0",
"MetaData": {
"CreateTime": "2015-07-23T10:58:12-07:00",
"LastUpdatedTime": "2015-07-23T10:58:12-07:00"
},
"Title": "Mr",
"GivenName": "James",
"MiddleName": "B",
"FamilyName": "King",
"Suffix": "Jr",
"FullyQualifiedName": "King's Groceries",
"CompanyName": "King Groceries",
"DisplayName": "King's Groceries",
"PrintOnCheckName": "King Groceries",
"Active": true,
"PrimaryPhone": {
"FreeFormNumber": "(555) 555-5555"
},
"PrimaryEmailAddr": {
"Address": "jdrew#myemail.com"
},
"DefaultTaxCodeRef": {
"value": "2"
}
},
"time": "2015-07-23T10:58:12.099-07:00"
}
Make sure you save that Id attribute, you'll need that later.
The process for creating Items is similar. Docs:
https://developer.intuit.com/docs/api/accounting/Item
Everything is just standard OAuth requests. Go grab an OAuth library for Rails and you should be all set.

Ruby: Should strings in a frozen array also be individually frozen?

Ruby 2.2.3, Rails 4.2.1
I have a large number of arrays of strings that I define as constants for use throughout an application. They are various sets of ISO country codes, language codes, that sort of thing, so two to four characters, numbered in the hundreds of unique values each.
The different arrays are collections of these, so NORTH_AMERICA_COUNTRY_CODES might be an array of a dozen of so country codes, AFRICA_COUNTRY_CODES might be an array of around 60. Many of them overlap (various versions of the Commonwealth countries, for example).
The arrays are used in comparison with other arbitrary arrays of country codes for logic such as "Subtract this list of countries from Africa".
So I'm wondering whether, when I generate these constants, I ought to freeze the strings within the arrays, so instead of:
WORLD_COUNTRIES = Countries.pluck(:country_code).freeze
... maybe ...
WORLD_COUNTRIES = Countries.pluck(:country_code).map{|c| c.freeze}.freeze
Is there a way of quantifying the potential benefits?
I considered using arrays of symbols instead of arrays of strings, but the arbitrary arrays that these are used with are stored in PostgreSQL text arrays, and it seems like I'd need to serialise those columns instead, or maybe override the getter and setter methods to change the values between arrays of strings and arrays of symbols. Ugh.
Edit
Testing results, in which I've attempted to benchmark three situations:
Comparing a frozen array of unfrozen strings with an unfrozen array of unfrozen strings
Comparing a frozen array of frozen strings with an unfrozen array of unfrozen strings
Comparing a frozen array of symbols with an unfrozen array of symbols (in case I bit the bullet and went all symbolic on this).
Any thoughts on methodology or interpretation gratefully received. I'm not sure whether the similarity in results between the first two indicates that they are in all respects the same, but I'd be keen on anything that can directly point to differences in memory allocation.
Script:
require 'benchmark'
country_list = ["AD", "AE", "AF", "AG", "AI", "AL", "AM", "AN", "AO", "AQ", "AR", "AS", "AT", "AU", "AW", "AX", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BL", "BM", "BN", "BO", "BQ", "BR", "BS", "BT", "BV", "BW", "BY", "BZ", "CA", "CC", "CD", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR", "CS", "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "EH", "ER", "ES", "ET", "FI", "FJ", "FK", "FM", "FO", "FR", "GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL", "GM", "GN", "GP", "GQ", "GR", "GS", "GT", "GU", "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS", "IT", "JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MF", "MG", "MH", "MK", "ML", "MM", "MN", "MO", "MP", "MQ", "MR", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NC", "NE", "NF", "NG", "NI", "NL", "NO", "NP", "NR", "NU", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PM", "PN", "PR", "PS", "PT", "PW", "PY", "QA", "RE", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SD", "SE", "SG", "SH", "SI", "SJ", "SK", "SL", "SM", "SN", "SO", "SR", "SS", "ST", "SV", "SX", "SY", "SZ", "TC", "TD", "TF", "TG", "TH", "TJ", "TK", "TL", "TM", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UM", "US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF", "WS", "YE", "YT", "YU", "ZA", "ZM", "ZW"]
FROZEN_ARRAY = country_list.dup.freeze
puts FROZEN_ARRAY.size
FROZEN_ARRAY_AND_STRINGS = country_list.dup.map{|x| x.freeze}.freeze
FROZEN_ARRAY_AND_SYMBOLS = country_list.dup.map{|x| x.to_sym}.freeze
comp_s = %w(AD AT BE CY EE FI FR DE ES GR IE IT LU LV MC ME MT NL PT SI SK SM VA)
comp_sym = %w(AD AT BE CY EE FI FR DE ES GR IE IT LU LV MC ME MT NL PT SI SK SM VA).map{|x| x.to_sym}
Benchmark.bm do |x|
x.report("frozen string" ) { 10000.times {|i| c = (FROZEN_ARRAY_AND_STRINGS & comp_s.dup) }}
x.report("unfrozen string") { 10000.times {|i| c = (FROZEN_ARRAY & comp_s.dup) }}
x.report("symbols" ) { 10000.times {|i| c = (FROZEN_ARRAY_AND_SYMBOLS & comp_sym.dup) }}
end
Benchmark.bmbm do |x|
x.report("frozen string" ) { 10000.times {|i| c = (FROZEN_ARRAY_AND_STRINGS & comp_s.dup) }}
x.report("unfrozen string") { 10000.times {|i| c = (FROZEN_ARRAY & comp_s.dup) }}
x.report("symbols" ) { 10000.times {|i| c = (FROZEN_ARRAY_AND_SYMBOLS & comp_sym.dup) }}
end
Result:
2.2.3 :001 > require 'benchmark'
=> false
2.2.3 :002 >
2.2.3 :003 > country_list = ["AD", "AE", "AF", "AG", "AI", "AL", "AM", "AN", "AO", "AQ", "AR", "AS", "AT", "AU", "AW", "AX", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BL", "BM", "BN", "BO", "BQ", "BR", "BS", "BT", "BV", "BW", "BY", "BZ", "CA", "CC", "CD", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR", "CS", "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "EH", "ER", "ES", "ET", "FI", "FJ", "FK", "FM", "FO", "FR", "GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL", "GM", "GN", "GP", "GQ", "GR", "GS", "GT", "GU", "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS", "IT", "JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MF", "MG", "MH", "MK", "ML", "MM", "MN", "MO", "MP", "MQ", "MR", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NC", "NE", "NF", "NG", "NI", "NL", "NO", "NP", "NR", "NU", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PM", "PN", "PR", "PS", "PT", "PW", "PY", "QA", "RE", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SD", "SE", "SG", "SH", "SI", "SJ", "SK", "SL", "SM", "SN", "SO", "SR", "SS", "ST", "SV", "SX", "SY", "SZ", "TC", "TD", "TF", "TG", "TH", "TJ", "TK", "TL", "TM", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UM", "US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF", "WS", "YE", "YT", "YU", "ZA", "ZM", "ZW"]
=> ["AD", "AE", "AF", "AG", "AI", "AL", "AM", "AN", "AO", "AQ", "AR", "AS", "AT", "AU", "AW", "AX", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BL", "BM", "BN", "BO", "BQ", "BR", "BS", "BT", "BV", "BW", "BY", "BZ", "CA", "CC", "CD", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR", "CS", "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "EH", "ER", "ES", "ET", "FI", "FJ", "FK", "FM", "FO", "FR", "GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL", "GM", "GN", "GP", "GQ", "GR", "GS", "GT", "GU", "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS", "IT", "JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MF", "MG", "MH", "MK", "ML", "MM", "MN", "MO", "MP", "MQ", "MR", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NC", "NE", "NF", "NG", "NI", "NL", "NO", "NP", "NR", "NU", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PM", "PN", "PR", "PS", "PT", "PW", "PY", "QA", "RE", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SD", "SE", "SG", "SH", "SI", "SJ", "SK", "SL", "SM", "SN", "SO", "SR", "SS", "ST", "SV", "SX", "SY", "SZ", "TC", "TD", "TF", "TG", "TH", "TJ", "TK", "TL", "TM", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UM", "US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF", "WS", "YE", "YT", "YU", "ZA", "ZM", "ZW"]
2.2.3 :004 > FROZEN_ARRAY = country_list.dup.freeze
=> ["AD", "AE", "AF", "AG", "AI", "AL", "AM", "AN", "AO", "AQ", "AR", "AS", "AT", "AU", "AW", "AX", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BL", "BM", "BN", "BO", "BQ", "BR", "BS", "BT", "BV", "BW", "BY", "BZ", "CA", "CC", "CD", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR", "CS", "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "EH", "ER", "ES", "ET", "FI", "FJ", "FK", "FM", "FO", "FR", "GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL", "GM", "GN", "GP", "GQ", "GR", "GS", "GT", "GU", "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS", "IT", "JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MF", "MG", "MH", "MK", "ML", "MM", "MN", "MO", "MP", "MQ", "MR", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NC", "NE", "NF", "NG", "NI", "NL", "NO", "NP", "NR", "NU", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PM", "PN", "PR", "PS", "PT", "PW", "PY", "QA", "RE", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SD", "SE", "SG", "SH", "SI", "SJ", "SK", "SL", "SM", "SN", "SO", "SR", "SS", "ST", "SV", "SX", "SY", "SZ", "TC", "TD", "TF", "TG", "TH", "TJ", "TK", "TL", "TM", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UM", "US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF", "WS", "YE", "YT", "YU", "ZA", "ZM", "ZW"]
2.2.3 :005 > puts FROZEN_ARRAY.size
252
=> nil
2.2.3 :006 > FROZEN_ARRAY_AND_STRINGS = country_list.dup.map{|x| x.freeze}.freeze
=> ["AD", "AE", "AF", "AG", "AI", "AL", "AM", "AN", "AO", "AQ", "AR", "AS", "AT", "AU", "AW", "AX", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BL", "BM", "BN", "BO", "BQ", "BR", "BS", "BT", "BV", "BW", "BY", "BZ", "CA", "CC", "CD", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR", "CS", "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "EH", "ER", "ES", "ET", "FI", "FJ", "FK", "FM", "FO", "FR", "GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL", "GM", "GN", "GP", "GQ", "GR", "GS", "GT", "GU", "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS", "IT", "JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MF", "MG", "MH", "MK", "ML", "MM", "MN", "MO", "MP", "MQ", "MR", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NC", "NE", "NF", "NG", "NI", "NL", "NO", "NP", "NR", "NU", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PM", "PN", "PR", "PS", "PT", "PW", "PY", "QA", "RE", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SD", "SE", "SG", "SH", "SI", "SJ", "SK", "SL", "SM", "SN", "SO", "SR", "SS", "ST", "SV", "SX", "SY", "SZ", "TC", "TD", "TF", "TG", "TH", "TJ", "TK", "TL", "TM", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UM", "US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF", "WS", "YE", "YT", "YU", "ZA", "ZM", "ZW"]
2.2.3 :007 > FROZEN_ARRAY_AND_SYMBOLS = country_list.dup.map{|x| x.to_sym}.freeze
=> [:AD, :AE, :AF, :AG, :AI, :AL, :AM, :AN, :AO, :AQ, :AR, :AS, :AT, :AU, :AW, :AX, :AZ, :BA, :BB, :BD, :BE, :BF, :BG, :BH, :BI, :BJ, :BL, :BM, :BN, :BO, :BQ, :BR, :BS, :BT, :BV, :BW, :BY, :BZ, :CA, :CC, :CD, :CF, :CG, :CH, :CI, :CK, :CL, :CM, :CN, :CO, :CR, :CS, :CU, :CV, :CW, :CX, :CY, :CZ, :DE, :DJ, :DK, :DM, :DO, :DZ, :EC, :EE, :EG, :EH, :ER, :ES, :ET, :FI, :FJ, :FK, :FM, :FO, :FR, :GA, :GB, :GD, :GE, :GF, :GG, :GH, :GI, :GL, :GM, :GN, :GP, :GQ, :GR, :GS, :GT, :GU, :GW, :GY, :HK, :HM, :HN, :HR, :HT, :HU, :ID, :IE, :IL, :IM, :IN, :IO, :IQ, :IR, :IS, :IT, :JE, :JM, :JO, :JP, :KE, :KG, :KH, :KI, :KM, :KN, :KP, :KR, :KW, :KY, :KZ, :LA, :LB, :LC, :LI, :LK, :LR, :LS, :LT, :LU, :LV, :LY, :MA, :MC, :MD, :ME, :MF, :MG, :MH, :MK, :ML, :MM, :MN, :MO, :MP, :MQ, :MR, :MS, :MT, :MU, :MV, :MW, :MX, :MY, :MZ, :NA, :NC, :NE, :NF, :NG, :NI, :NL, :NO, :NP, :NR, :NU, :NZ, :OM, :PA, :PE, :PF, :PG, :PH, :PK, :PL, :PM, :PN, :PR, :PS, :PT, :PW, :PY, :QA, :RE, :RO, :RS, :RU, :RW, :SA, :SB, :SC, :SD, :SE, :SG, :SH, :SI, :SJ, :SK, :SL, :SM, :SN, :SO, :SR, :SS, :ST, :SV, :SX, :SY, :SZ, :TC, :TD, :TF, :TG, :TH, :TJ, :TK, :TL, :TM, :TN, :TO, :TR, :TT, :TV, :TW, :TZ, :UA, :UG, :UM, :US, :UY, :UZ, :VA, :VC, :VE, :VG, :VI, :VN, :VU, :WF, :WS, :YE, :YT, :YU, :ZA, :ZM, :ZW]
2.2.3 :008 > comp_s = %w(AD AT BE CY EE FI FR DE ES GR IE IT LU LV MC ME MT NL PT SI SK SM VA)
=> ["AD", "AT", "BE", "CY", "EE", "FI", "FR", "DE", "ES", "GR", "IE", "IT", "LU", "LV", "MC", "ME", "MT", "NL", "PT", "SI", "SK", "SM", "VA"]
2.2.3 :009 > comp_sym = %w(AD AT BE CY EE FI FR DE ES GR IE IT LU LV MC ME MT NL PT SI SK SM VA).map{|x| x.to_sym}
=> [:AD, :AT, :BE, :CY, :EE, :FI, :FR, :DE, :ES, :GR, :IE, :IT, :LU, :LV, :MC, :ME, :MT, :NL, :PT, :SI, :SK, :SM, :VA]
2.2.3 :010 >
2.2.3 :011 >
2.2.3 :012 > Benchmark.bm do |x|
2.2.3 :013 > x.report("frozen string" ) { 10000.times {|i| c = (FROZEN_ARRAY_AND_STRINGS & comp_s.dup) }}
2.2.3 :014?> x.report("unfrozen string") { 10000.times {|i| c = (FROZEN_ARRAY & comp_s.dup) }}
2.2.3 :015?> x.report("symbols" ) { 10000.times {|i| c = (FROZEN_ARRAY_AND_SYMBOLS & comp_sym.dup) }}
2.2.3 :016?> end
user system total real
frozen string 0.190000 0.000000 0.190000 ( 0.194141)
unfrozen string 0.170000 0.010000 0.180000 ( 0.174675)
symbols 0.080000 0.000000 0.080000 ( 0.081507)
=> [#<Benchmark::Tms:0x007f810c3aca70 #label="frozen string", #real=0.1941408810671419, #cstime=0.0, #cutime=0.0, #stime=0.0, #utime=0.1899999999999995, #total=0.1899999999999995>, #<Benchmark::Tms:0x007f810c82b538 #label="unfrozen string", #real=0.1746752569451928, #cstime=0.0, #cutime=0.0, #stime=0.010000000000000009, #utime=0.16999999999999993, #total=0.17999999999999994>, #<Benchmark::Tms:0x007f810af2cfa0 #label="symbols", #real=0.08150708093307912, #cstime=0.0, #cutime=0.0, #stime=0.0, #utime=0.08000000000000007, #total=0.08000000000000007>]
2.2.3 :017 >
2.2.3 :018 >
2.2.3 :019 > Benchmark.bmbm do |x|
2.2.3 :020 > x.report("frozen string" ) { 10000.times {|i| c = (FROZEN_ARRAY_AND_STRINGS & comp_s.dup) }}
2.2.3 :021?> x.report("unfrozen string") { 10000.times {|i| c = (FROZEN_ARRAY & comp_s.dup) }}
2.2.3 :022?> x.report("symbols" ) { 10000.times {|i| c = (FROZEN_ARRAY_AND_SYMBOLS & comp_sym.dup) }}
2.2.3 :023?> end
Rehearsal ---------------------------------------------------
frozen string 0.180000 0.000000 0.180000 ( 0.183846)
unfrozen string 0.200000 0.000000 0.200000 ( 0.196311)
symbols 0.080000 0.000000 0.080000 ( 0.082794)
------------------------------------------ total: 0.460000sec
user system total real
frozen string 0.160000 0.000000 0.160000 ( 0.167051)
unfrozen string 0.170000 0.000000 0.170000 ( 0.171601)
symbols 0.080000 0.000000 0.080000 ( 0.078746)
=> [#<Benchmark::Tms:0x007f811022a388 #label="frozen string", #real=0.1670510449912399, #cstime=0.0, #cutime=0.0, #stime=0.0, #utime=0.16000000000000014, #total=0.16000000000000014>, #<Benchmark::Tms:0x007f811022a4c8 #label="unfrozen string", #real=0.17160122003406286, #cstime=0.0, #cutime=0.0, #stime=0.0, #utime=0.16999999999999993, #total=0.16999999999999993>, #<Benchmark::Tms:0x007f8108eb1c58 #label="symbols", #real=0.07874645793344826, #cstime=0.0, #cutime=0.0, #stime=0.0, #utime=0.08000000000000007, #total=0.08000000000000007>]
2.2.3 :024 >
2.2.3 :025 >
2.2.3 :026 >
Since you're dealing with a small number of values, and since the performance benefits of symbols are evident from your testing, just go with symbols.
BTW, you can use map(&:to_sym) instead of map {|x| x.to_sym}.

Resources