Re:Data munging in Perl 6 vs. Perl 5
by Skunkleton on Tuesday December 09, 2014 @05:16PM
(#8726207)
I feel like python provides a more readable solution.
[ Parent
| on HN ]
A Haskell solution, though I'm sure someone can do better ;)
Perhaps I'll clean it up using printf/format[0] later.
{-# LANGUAGE OverloadedStrings #-}
import Control.Monad (liftM)
import qualified Data.HashMap.Lazy as H
import Data.List (sort)
import Data.Maybe (fromMaybe)
import Data.Monoid ((<>))
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
import Prelude
main :: IO ()
main = do
gradesMap <- liftM
(H.fromList . map ((\(x:y:_) -> (x,y)) . T.splitOn "\t") . T.lines)
(TIO.readFile "example.txt")
let failingNames = H.keys $ H.filter ((== F) . T.take 1) gradesMap
gradeTotals = foldl
(\m k -> H.insertWith (+) (T.take 1 k) 1 m)
H.empty
(H.elems gradesMap)
TIO.putStrLn $ "Zsófia's grades: " <>
fromMaybe "N/A" (H.lookup "Zsófia" gradesMap)
TIO.putStrLn "List of students with a failing grade:"
TIO.putStrLn $ " " <> T.intercalate ", " failingNames
TIO.putStrLn "Distribution of grades by letter:"
mapM_ (\(k,v) -> TIO.putStrLn $ " " <> k <> ": " <> (T.pack . show $ v) <> " students")
(sort . H.toList $ gradeTotals)
0: http://hackage.haskell.org/package/formattingA working version with some stuff improved - groupby implemented, len() instead of sum(), a less squished version of printing, "student(s)" added:
#!/usr/bin/env python3
from collections import defaultdict
def invert_dict(data):
res = defaultdict(list)
for k, v in data.items():
res[v[0]].append(k)
return res
with open('data.txt', 'r') as f:
data = dict(x.split() for x in f if x.strip())
print("Zsófia's grade:", data["Zsófia"])
print("List of students with a failing grade:")
print(" " ,end="")
print(*[x for x in data.keys() if data[x] == 'F'], sep=", ")
print("Distribution of grades by letter:")
grouped = invert_dict(data)
for k, g in sorted(grouped.items()):
print(" {}: {} student{}".format(k, len(g), 's' if len(g) > 1 else ''))No need for `invert_dict`; you're just counting so `collections.Counter` would work fine:
from collections import Counter
with open('data.txt', 'r') as datafile:
students = dict(line.rsplit(maxsplit=1) for line in datafile)
failing = [name for name, grade in students.items() if grade >= 'E']
grade_counts = Counter(grade[0] for grade in students.values())
print("Zsófia's grade:", students["Zsófia"])
print("List of students with a failing grade:")
print(" " + ", ".join(failing))
print("Distribution of grades by letter:")
for grade, count in sorted(grade_counts.items()):
print(" {}: {} student{}".format(grade, count, 's' * (count != 1)))