Улучшения в коде, имеющие итерацию вложенных хэшей и массивов ввода - PullRequest
1 голос
/ 11 марта 2019

Я мог бы использовать любые улучшения для улучшения своего кода.Я думаю, что большинство методов имеют одинаковую структуру, но я не получаю желаемого результата, поэтому любая помощь будет отличной.Если вы хотите посмотреть упражнение онлайн, оно называется «Вложенная итерация бакалавра».Я действительно понятия не имею, почему я не получаю желаемый результат, мне кажется, моя разработка имеет смысл.

для get_first_name_of_season_winner , независимо от того, через какие аргументы я передаю, когда яНазовите это, я всегда получаю «Бет Смоллс» в качестве выхода, когда это не должно быть так.Если я пройду «Сезон 29», результат будет «Эшли Йейтс»

для метода get_contestant_name , это то же самое.Он всегда возвращает «Бет Смоллс» независимо от того, через какое занятие я прохожу.Например, если я назову это так

get_contestant_name(thebachelor, "Chiropractic Assistant" )

, он должен вернуть "Becca Tilley" в качестве вывода, но это не так.

для count_contestant_by_hometown , он должен возвращать количество участников из родного города, которые были переданы в методе, однако, независимо от того, какой аргумент я передаю, я получаю число 4.

для get_occupation , он должен возвращать имя человека, соответствующего родному городу, который передается в методе, но я всегда получаю "Бет Смоллс" независимо от того, через какой родной город я его прохожу.

Последний метод, я понятия не имею, как это сделать.Он принимает два аргумента - хеш данных и строку сезона.Переберите хеш и верните средний возраст всех участников этого сезона.

thebachelor = { 
  "season 30": [
    {
      "name":      "Beth Smalls",
      "age":       "26",
      "hometown":  "Great Falls, Virginia",
      "occupation": "Nanny/Freelance Journalist",
      "status":    "Winner"
    },
    {
      "name":       "Becca Tilley",
      "age":        "27",
      "hometown":   "Shreveport, Louisiana",
      "occupation": "Chiropractic Assistant",
      "status":     "Eliminated Week 8"
    }
  ],
  "season 29": [
    {
      "name":      "Ashley Yeats",
      "age":       "24",
      "hometown":  "Denver, Colorado",
      "occupation": "Dental Assitant",
      "status":    "Winner"
    },
    {
      "name":       "Sam Grover",
      "age":        "29",
      "hometown":   "New York, New York",
      "occupation": "Entertainer",
      "status":     "Eliminated Week 6"
    }
  ]
}

Теперь методы.get_first_name_of_season_winner is

def get_first_name_of_season_winner(data, season)

    #this method returns the first name of that seasons winner
    #pass the season of the show, and then it returns only th FIRST NAME of the winner for that season
    #iterate through the inital hash to access the season number
    #then iterate through the array, to access the hash inside
    #acess the "status" to get the output
  data.each do |season, contestant_Data|
    contestant_Data.each do |a|
      a.each do |attribute, value|
        if value == "Winner"
          return a[:name]
        end
      end 
    end
  end
end

get_first_name_of_season_winner(thebachelor, "season 29") #returns the full name of only "Beth Smalls"

get_contestant_name is:

def get_contestant_name(data, occupation) #this method takes in the data hash and an occupation string and returns the name of the woman who has that occupation

    #iterate through the initial hash to access the seasons
    #iterate through the seasons to access the arrays inside
    #access the occupation element of the array
    #return the person who has the occupation

    data.each do |season, contestant_data|
        contestant_data.each do |a|
            a.each do |attribute, value|
                if attribute == :occupation
                    return a[:name]
                end 
            end 
        end 
    end
end

get_contestant_name(thebachelor, "Chiropractic Assistant" ) #returns the full name of only "Beth Smalls"

count_contestant_by_hometown is:

def count_contestant_by_hometown(data, hometown) #this method should return the number of contestants from the hometown passed
    #include a counter variable
    #iterate through the hash to access the seasons
    #access the array 
    #access the hometown key in the hash
    #keep count

    counter = 0 
    data.each do |season, contestant_data|
        contestant_data.each do |a|
            a.each do |attribute, value|
                if attribute == :hometown
                    counter += 1
                end
            end 
        end 
    end 

    return counter
end 
count_contestant_by_hometown(thebachelor, "Denver, Colorado") #returns the number 4, I have no idea why

get_occupation is:

def get_occupation(data, hometown) #should return the occupation of of the first contestant who hails from the hometown

    data.each do |season, contestant_data|
        contestant_data.each do |a|
            a.each do |attribute, value|
                if attribute == :hometown
                    return a[:name]
                end 
            end 
        end 
    end

end 
get_occupation(thebachelor, "Denver, Colorado") #returns "Beth Smalls" when it should return "Ashley Yeats"

average_age_for_season - это:

def average_age_for_season(data, season) #returns the average age of all contestants for that season

Ответы [ 3 ]

1 голос
/ 11 марта 2019

Я думаю, что большая проблема возникает из-за данных, которые вы передаете. Возьмите, например, рабочее решение для вашей последней проблемы.

Чтобы получить данные за один сезон, вы можете использовать:

def average_age_for(data, season)
  contestants = data[season]
  contestants.sum { |contestant| contestant[:age].to_f } / contestants.count
end

average_age_for(thebatchelor, :"season 30")
#=> 26.5

Обратите внимание, что вам нужно передать :"season 30", а не просто "season 30".Это потому, что ваши данные используют символизированные строки в качестве ключей, а не просто строки.

Замените ключи ваших данных строками:

thebachelor = { 
  "season 30" => [
    {
      "name" =>      "Beth Smalls",
      "age" =>       "26",
      "hometown" =>  "Great Falls, Virginia",
      "occupation" => "Nanny/Freelance Journalist",
      "status" =>    "Winner"
    },
    {
      "name" =>       "Becca Tilley",
      "age" =>        "27",
      "hometown" =>   "Shreveport, Louisiana",
      "occupation" => "Chiropractic Assistant",
      "status" =>     "Eliminated Week 8"
    }
  ],
  "season 29" => [
    {
      "name" =>      "Ashley Yeats",
      "age" =>       "24",
      "hometown" =>  "Denver, Colorado",
      "occupation" => "Dental Assitant",
      "status" =>    "Winner"
    },
    {
      "name" =>       "Sam Grover",
      "age" =>        "29",
      "hometown" =>   "New York, New York",
      "occupation" => "Entertainer",
      "status" =>     "Eliminated Week 6"
    }
  ]
}

Затем найдите строку в методе:

def average_age_for(data, season)
  contestants = data[season]
  #                                        vvvvvvv
  contestants.sum { |contestant| contestant["age"].to_f } / contestants.count
  #                                        ^^^^^^^
end

И это приобретает форму.


Затем можно сделать:

1)

def get_first_name_of_season_winner(data, season)
  data[season].detect { |contestant| contestant["status"] == "Winner" }["name"].split.first
end

get_first_name_of_season_winner(thebachelor, "season 29")
#=> "Ashley"

2)

def get_contestant_name(data, occupation)
  data.values.flatten.detect { |contestant| contestant["occupation"] == occupation }
end

get_contestant_name(thebachelor, "Chiropractic Assistant")
#=> {"name"=>"Becca Tilley", "age"=>"27", "hometown"=>"Shreveport, Louisiana", "occupation"=>"Chiropractic Assistant", "status"=>"Eliminated Week 8"}

3)

def count_contestant_by_hometown(data, town)
  data.values.flatten.select { |contestant| contestant["hometown"] == town }.count
end

count_contestant_by_hometown(thebachelor, "New York, New York")
#=> 1

4)

def get_occupation(data, hometown)
  data.values.flatten.detect { |contestant| contestant["hometown"] == hometown }["occupation"]
end

get_occupation(thebachelor, "New York, New York")
#=> "Entertainer"
0 голосов
/ 12 марта 2019

Обобщенное и& оптимизированное решение :

Следующий метод будет работать, чтобы получить все, что вам нужно от вашего хэша thebachelor,

def get_information(data, required, season, optional, hash= {})
  data = season.nil? ? data.values.flatten : data[season]
  selected = data.select { |x| (hash.inject(true) { |m, (k,v)| m &&= (x[k] == v) }) }
  required_data = selected.map { |x| x[required] }
  if optional == :average && required == :age
    (required_data.map(&:to_i).sum / required_data.count.to_f).round(2)
  else
    (optional == :count) ? required_data.count : required_data
  end
end

Данные должны быть предоставлены, как показано ниже,

  1. data - ввод хеша, из которого вы хотите извлечь данные
  2. обязательно - выведите внутренний хеш-атрибут, который вы хотите вывести.
  3. сезон - если вы хотите получить данные, относящиеся к конкретному сезону, укажите сезон, иначе ноль получить за весь сезон.
  4. Необязательно - можно установить ноль, если вы не хотите считать или усреднить. В противном случае передайте :count или :average в качестве необязательного аргумента.
  5. hash - опция фильтра. Если вы хотите фильтровать внутренние данные по таким атрибутам, как :hometown или :status или :occupation. Просто предоставь это. в противном случае будет установлен пустой хеш.

См. Примеры ниже,

# Get name of season winner for season 'season 29'
get_information(thebachelor, :name, :'season 29', nil, status: 'Winner')
# => ["Ashley Yeats"]

# Get name of all winners irrespective of season
get_information(thebachelor, :name, nil, nil, status: 'Winner')
# => ["Beth Smalls", "Ashley Yeats"]

# Get contestant name for occupation "Chiropractic Assistant"
get_information(thebachelor, :name, nil, nil, occupation: "Chiropractic Assistant")
# => ["Becca Tilley"]

# Count contestant by home town "Denver, Colorado"
get_information(thebachelor, :name, nil, :count, hometown: "Denver, Colorado")
# => 1

# Get occupation of contestant who hails from hometown "Denver, Colorado"
get_information(thebachelor, :occupation, nil, nil, hometown: "Denver, Colorado")
# => ["Dental Assitant"]

# Get Average age for season :"season 29"
get_information(thebachelor, :age, :"season 29", :average)
# => 26.5

Этот метод дает больше, чем вы задали в своем вопросе.

0 голосов
/ 11 марта 2019

Во-первых, я бы переформатировал ваши данные, чтобы их было легко выбирать / обнаруживать:

data = data.map { |key, value| value.transform_keys(&:to_sym).merge(season: key) }

, поэтому теперь это выглядит как

[{
  season:    "season 30",
  name:      "Beth Smalls",
  age:       "26",
  hometown:  "Great Falls, Virginia",
  occupation: "Nanny/Freelance Journalist",
  status:    "Winner"
},...
]

Теперь гораздо проще фильтровать и обнаруживать:

def get_first_name_of_season_winner(data, season)
  p = ->(v) { v[:season] == season && v[:status] == 'Winner' }
  data.detect(&p)[:name][/\w+/]
end

def get_contestant_name(data, occupation)
  p = ->(v) { v[:occupation] == occupation }
  data.detect(&p)[:name]
end

def count_contestant_by_hometown(data, hometown)
  p = ->(v) { v[:hometown] = hometown }
  data.select(&p).count
end

def get_occupation(data, hometown)
  p = ->(v) { v[:hometown] = hometown }
  data.detect(&p)[:occupation]
end

def average_age_for_season(data, season)
  p = ->(v) { v[:season] = season }
  ages = data.select(&p).map { |datum| datum[:age] }
  ages.sum.fdiv(ages.count) unless ages.empty?
end

В общем, все эти проблемы бывают двух типов: 1. По массиву данных найти все элементы, удовлетворяющие определенному условию 2. По массиву данных найти первый элемент, которыйудовлетворяет определенному условию

И вы всегда решаете их с помощью выбора / обнаружения и блока / процесса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...