#haskell
#haskell
Вопрос:
Я пытаюсь вычислить среднее значение элементов списка. Учитывая текстовый текст, где у меня есть имя, а затем числа для вычисления среднего:
Bob 5 6 9 10 5
Alice 10 3 5 6 8
Kate 2 4
Я использую функцию words для получения списка входного файла, чтобы я мог его обработать.
Я пытаюсь создать список кортежей для вычисления среднего значения с помощью функции composeList, но я получаю только первый элемент:
[("Bob",[5.0,6.0,9.0,10.0,5.0])]
Я не знаю, как получить список кортежей, а затем вычислить среднее значение, чтобы получить
[(«Боб», 7.0), («Алиса», 6.5), «Кейт», 7.75)]
Вот что у меня есть до сих пор:
import qualified Data.Text as Text
import qualified Data.Text.IO as Text
import Data.String
readLines :: FilePath -> IO [String]
readLines = fmap lines . readFile
calculateMean :: [Double] -> Double
calculateMean [] = 0
calculateMean (a) = sum a / fromIntegral(length a)
--calculateMeanList :: [String] -> (String,[Double])
--calculateMeanList (a) = (head $ words $ head a, calculateMean $ convertNumeric $ tail $ words $ head $ a)
convertNumeric :: [String] -> [Double]
convertNumeric = map read
composeList :: [String] -> [(String, [Double])]
composeList (a) = [(head $ words $ head $ a, convertNumeric $ tail $ words $ head $ a)]
main = do
ls <- readLines "puntuaciones.txt"
print $ words $ head $ ls
print $ composeList ls
Комментарии:
1. Сначала напишите функцию, которая может превратить одну пару
("Bob",[5.0,6.0,9.0,10.0,5.0])
в нужную("Bob",7.0)
. Должно быть что-то вродеfoo (name, values) = (... , ...)
. Затемmap
поверх списка пар.
Ответ №1:
Вы берете только слова head
, поэтому, конечно, вы получаете только первый элемент. Вы должны отображать words
функцию по строкам:
import qualified Data.Text as Text
import qualified Data.Text.IO as Text
import Data.String
readLines :: FilePath -> IO [String]
readLines = fmap lines . readFile
calculateMean :: [Double] -> Double
calculateMean [] = 0
calculateMean (a) = sum a / fromIntegral(length a)
convertNumeric :: [String] -> [Double]
convertNumeric = map read
composeList :: [String] -> [(String, [Double])]
-- could be written with a map but list comprehension is cleaner
composeList a = [(head curWords, convertNumeric $ tail curWords) | curWords <- map words a]
main = do
ls <- readLines "puntuaciones.txt"
let composed = composeList ls
print composed
-- this could also be written with a list comprehension
-- [(a, calculateMean b) | (a, b) <- composed]
print $ map ((a, b) -> (a, calculateMean b)) composed
Комментарии:
1. Хорошо, я вижу, что я делал неправильно. Спасибо! Я пытался создать функцию для этого и заменить созданную вами лямбда-функцию, но, думаю, я тоже делаю это неправильно:
calculateMeanList2 :: (String,[Double]) -> (String, Double) calculateMeanList2 (a, b) = map (l -> ((a, calculateMean b) l))
2. Кроме того, ваша лямбда неверна, потому что вам нужно сохранить первый элемент кортежа вне карты, а затем просто взять среднее значение списка, чтобы оно выглядело как
calculateMeanList2 (a, b) = (a, calculateMean b)
3. Но есть ли способ вызвать map для этой функции calculateMeanList2? Я пытаюсь инкапсулировать все это в функцию.
4.
calculateMeanList2
просто работает с кортежем. Затем вы можете простоmap calculateMeanList2 composed
изменить полный список.