DEV Community

dev.to staff
dev.to staff

Posted on

Daily Challenge #216 - Rainfall

data and data1 are two strings with rainfall records of a few cities for months from January to December. The records of towns are separated by \n. The name of each town is followed by :.

const data = 
     "Rome:Jan 81.2,Feb 63.2,Mar 70.3,Apr 55.7,May 53.0,Jun 36.4,Jul 17.5,Aug 27.5,Sep 60.9,Oct 117.7,Nov 111.0,Dec 97.9" + "\n" +
     "London:Jan 48.0,Feb 38.9,Mar 39.9,Apr 42.2,May 47.3,Jun 52.1,Jul 59.5,Aug 57.2,Sep 55.4,Oct 62.0,Nov 59.0,Dec 52.9" + "\n" +
     "Paris:Jan 182.3,Feb 120.6,Mar 158.1,Apr 204.9,May 323.1,Jun 300.5,Jul 236.8,Aug 192.9,Sep 66.3,Oct 63.3,Nov 83.2,Dec 154.7" + "\n" +
     "NY:Jan 108.7,Feb 101.8,Mar 131.9,Apr 93.5,May 98.8,Jun 93.6,Jul 102.2,Aug 131.8,Sep 92.0,Oct 82.3,Nov 107.8,Dec 94.2" + "\n" +
     "Vancouver:Jan 145.7,Feb 121.4,Mar 102.3,Apr 69.2,May 55.8,Jun 47.1,Jul 31.3,Aug 37.0,Sep 59.6,Oct 116.3,Nov 154.6,Dec 171.5" + "\n" +
     "Sydney:Jan 103.4,Feb 111.0,Mar 131.3,Apr 129.7,May 123.0,Jun 129.2,Jul 102.8,Aug 80.3,Sep 69.3,Oct 82.6,Nov 81.4,Dec 78.2" + "\n" +
     "Bangkok:Jan 10.6,Feb 28.2,Mar 30.7,Apr 71.8,May 189.4,Jun 151.7,Jul 158.2,Aug 187.0,Sep 319.9,Oct 230.8,Nov 57.3,Dec 9.4" + "\n" +
     "Tokyo:Jan 49.9,Feb 71.5,Mar 106.4,Apr 129.2,May 144.0,Jun 176.0,Jul 135.6,Aug 148.5,Sep 216.4,Oct 194.1,Nov 95.6,Dec 54.4" + "\n" +
     "Beijing:Jan 3.9,Feb 4.7,Mar 8.2,Apr 18.4,May 33.0,Jun 78.1,Jul 224.3,Aug 170.0,Sep 58.4,Oct 18.0,Nov 9.3,Dec 2.7" + "\n" +
     "Lima:Jan 1.2,Feb 0.9,Mar 0.7,Apr 0.4,May 0.6,Jun 1.8,Jul 4.4,Aug 3.1,Sep 3.3,Oct 1.7,Nov 0.5,Dec 0.7";
const data1 =
     "Rome:Jan 90.2,Feb 73.2,Mar 80.3,Apr 55.7,May 53.0,Jun 36.4,Jul 17.5,Aug 27.5,Sep 60.9,Oct 147.7,Nov 121.0,Dec 97.9" + "\n" +
     "London:Jan 58.0,Feb 38.9,Mar 49.9,Apr 42.2,May 67.3,Jun 52.1,Jul 59.5,Aug 77.2,Sep 55.4,Oct 62.0,Nov 69.0,Dec 52.9" + "\n" +
     "Paris:Jan 182.3,Feb 120.6,Mar 188.1,Apr 204.9,May 323.1,Jun 350.5,Jul 336.8,Aug 192.9,Sep 66.3,Oct 63.3,Nov 83.2,Dec 154.7" + "\n" +
     "NY:Jan 128.7,Feb 121.8,Mar 151.9,Apr 93.5,May 98.8,Jun 93.6,Jul 142.2,Aug 131.8,Sep 92.0,Oct 82.3,Nov 107.8,Dec 94.2" + "\n" +
     "Vancouver:Jan 155.7,Feb 121.4,Mar 132.3,Apr 69.2,May 85.8,Jun 47.1,Jul 31.3,Aug 37.0,Sep 69.6,Oct 116.3,Nov 154.6,Dec 171.5" + "\n" +
     "Sydney:Jan 123.4,Feb 111.0,Mar 151.3,Apr 129.7,May 123.0,Jun 159.2,Jul 102.8,Aug 90.3,Sep 69.3,Oct 82.6,Nov 81.4,Dec 78.2" + "\n" +
     "Bangkok:Jan 20.6,Feb 28.2,Mar 40.7,Apr 81.8,May 189.4,Jun 151.7,Jul 198.2,Aug 197.0,Sep 319.9,Oct 230.8,Nov 57.3,Dec 9.4" + "\n" +
     "Tokyo:Jan 59.9,Feb 81.5,Mar 106.4,Apr 139.2,May 144.0,Jun 186.0,Jul 155.6,Aug 148.5,Sep 216.4,Oct 194.1,Nov 95.6,Dec 54.4" + "\n" +
     "Beijing:Jan 13.9,Feb 14.7,Mar 18.2,Apr 18.4,May 43.0,Jun 88.1,Jul 224.3,Aug 170.0,Sep 58.4,Oct 38.0,Nov 19.3,Dec 2.7" + "\n" +
     "Lima:Jan 11.2,Feb 10.9,Mar 10.7,Apr 10.4,May 10.6,Jun 11.8,Jul 14.4,Aug 13.1,Sep 23.3,Oct 1.7,Nov 0.5,Dec 10.7";
const towns = ["Rome", "London", "Paris", "NY", "Vancouver", "Sydney", "Bangkok", "Tokyo",
               "Beijing", "Lima", "Montevideo", "Caracas", "Madrid", "Berlin"]

function: mean(town, string) should return the average of rainfall for the city town and the string data or data1.

function: variance(town, string) should return the variance of rainfall for the city town and the string data or data1.

If functions mean or variance have as parameter town a city which has no records, return -1.

A reference to help: http://www.mathsisfun.com/data/standard-deviation.html
data and data1 (can be named d0 and d1 depending on the language) are adapted from: http://www.worldclimate.com

Examples

mean("London", data) => 51.19(9999999999996)
variance("London", data) => 57.42(833333333374)

Tests

mean(Rome, data1);
mean(Beijing, data);

variance(Beijing, data1);
variance(Lima, data);

Good luck!


This challenge comes from g964 on CodeWars. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

Top comments (12)

Collapse
 
vidit1999 profile image
Vidit Sarkar

Python solution

# load the data in a dictionary
# dict keys are towns
# and value is another dict with keys 'mean' and 'variancne'
# and values with mean and variance of the respective towns
# Example:
# to_dict_load(data) ->
# {'Rome': {'mean': 66.02499999999999, 'variance': 915.3852083333335},
# 'London': {'mean': 51.199999999999996, 'variance': 57.428333333333335} ... }
def to_dict_load(data):
    all_towns = data.split("\n")
    town_wise = {}
    for i in range(len(all_towns)):
        town_name, values = all_towns[i].split(":")
        values = values.split(",")
        vals = [float(v.split(" ")[1]) for v in values]
        mean = sum(vals)/len(vals)
        variance= sum(map(lambda x : (x-mean)*(x-mean), vals))/len(vals)
        town_wise[town_name] = {'mean': mean, 'variance': variance}
    return town_wise

# returns mean of rainfall in a town according to data
def mean(town, data):
    dt = to_dict_load(data)
    if town in dt:
        return dt[town]['mean']
    return -1

# returns variance of rainfall in a town according to data
def variance(town, data):
    dt = to_dict_load(data)
    if town in dt:
        return dt[town]['variance']
    return -1
Collapse
 
mellen profile image
Matt Ellen • Edited

Javascript with regex

function getData(rfd)
{
  let lines = rfd.split('\n');
  let cmap = new Map(lines.map(l => 
                               {
                                 let parts = l.split(':');
                                 return [parts[0], parts[1].split(/[^0-9.]+/)
                                                           .filter(v => v.length > 0)
                                                           .map(v => parseFloat(v))]
                               }));
  return cmap;  
}

function mean(country, rainfalldata)
{
  let d = getData(rainfalldata).get(country);
  if(!d)
  {
    return -1;
  }
  return d.reduce((acc, v) => acc + v, 0) / d.length;
}

function variance(country, rainfalldata)
{
  let m = mean(country, rainfalldata);
  if(m === -1)
  {
    return -1;
  }
  let d = getData(rainfalldata).get(country);
  return d.map(v => (v - m) * (v - m)).reduce((acc, v) => acc + v, 0) / (d.length)
}
Collapse
 
differentmatt profile image
Matt Lott

Fyi, you can add language specific syntax styling immediately after the first code back-ticks.

github.com/adam-p/markdown-here/wi...

Collapse
 
mellen profile image
Matt Ellen

Ah! I hadn't closed the three back ticks!

Collapse
 
mellen profile image
Matt Ellen

Thanks, Matt. I tried that, and if you see my other posts you'll see I was successful, but it's not working for this one for some reason

Collapse
 
differentmatt profile image
Matt Lott

JS solution

const parseData = (string) => {
  // Return map of cities and their rainfalls, assumes well-formed data
  return string.split('\n').map(line => line.split(':'))
    .map(cityMonths => {
      return {
        city: cityMonths[0],
        rainfalls: cityMonths[1].split(',')
          .map(month => parseFloat(month.split(' ')[1]))
          .filter(r => !isNaN(r))
      }
    })
    .reduce((m, cityRainfalls) => {
      m[cityRainfalls.city] = cityRainfalls.rainfalls
      return m
    }, {})
}

const calcMean = (nums) => nums.reduce((t, n) => t + n, 0) / nums.length

const calcVariance = (nums) => {
  const mean = calcMean(nums)
  return calcMean(nums.map(num => Math.pow(num - mean, 2)))
}

const mean = (town, string) => {
  const cityRainfallsMap = parseData(string)
  if (!cityRainfallsMap[town] || cityRainfallsMap[town].length < 1) return -1
  return calcMean(cityRainfallsMap[town])
}

const variance = (town, string) => {
  const cityRainfallsMap = parseData(string)
  if (!cityRainfallsMap[town] || cityRainfallsMap[town].length < 1) return -1
  return calcVariance(cityRainfallsMap[town])
}


// Tests assume data, data1 in scope

const test = (fn, town, string, expected) => {
  const result = fn(town, string)
  console.log(`${town} ${result} === ${expected} ?`)
}

test(variance, "London", data, 57.42833333333374)
test(mean, "London", data, 51.199999999999996)

test(mean, "Seattle", data, -1)
test(variance, "Seattle", data, -1)

test(mean, "Seattle", "Seattle:", -1)
test(variance, "Seattle", "Seattle:", -1)

test(variance, 'Beijing', data1, '4437.0380555556')
test(variance, 'Lima', data, '1.5790972222222')
Collapse
 
kesprit profile image
kesprit

My Swift solution, not the best ☹️:

func fetchCity(datas: String) -> [String: [Double]] {
    func fetchCityDatas(datas: String) -> [Double] {
        datas.split(separator: ",").map {
            Double($0.split(separator: .init(" ")).last ?? "") ?? 0
        }
    }

    return data.split(separator: "\n").reduce(into: [String:[Double]]()) {
        let data = $1.split(separator: ":")
        $0[String(data.first ?? "")] = fetchCityDatas(datas: String(data.last ?? ""))
    }
}

func mean(town: String, datas: String) -> Double {
    let convertedDatas = fetchCity(datas: datas)
    guard convertedDatas.contains(where: { $0.key == town }), let townDatas = convertedDatas[town] else { return -1 }

    let sum = townDatas.reduce(into: 0.0) { $0 += $1 }

    return sum / Double(townDatas.count)
}

func variance(town: String, datas: String) -> Double {
    let meanValue = mean(town: town, datas: datas)
    let convertedCities = fetchCity(datas: datas)
    guard let convertedDatas = convertedCities[town] else { return 0 }

    return convertedDatas.map { pow((meanValue - $0),2) }
        .reduce(into: 0.0) { $0 += $1 } / Double(convertedDatas.count)
}

mean(town: "Rome",datas: data1)
mean(town: "Beijing",datas: data)
variance(town: "Beijing",datas: data1)
variance(town: "Lima",datas: data)
Collapse
 
empereol profile image
Empereol

TypeScript

/**
 * Math Utilities
 */
interface Math {
  mean(...values: number[]): number;
  variance(...values: number[]): number;
}

Math.mean = (...values: number[]): number => values.reduce((t, v) => (t += v), 0) / values.length;

Math.variance = (...values: number[]): number => {
  const mean = Math.mean(...values);
  return Math.mean(...values.map(v => (v - mean) ** 2));
};

/**
 * Rainfall
 */
interface RainData {
  town: string;
  values: number[];
}

function createRainData(data: string): RainData[] {
  return data.split(/\n/).map(line => ({
    town: line.split(':')[0].trim(),
    values: line.match(/\d+\.\d+/gi).map(Number)
  }));
}

function getRainfall(town: string, data: string): number[] {
  const rainData = createRainData(data).find(d => d.town === town);
  return rainData ? rainData.values : [-1];
}

function mean(town: string, data: string): number {
  return Math.mean(...getRainfall(town, data));
}

function variance(town: string, data: string): number {
  return Math.variance(...getRainfall(town, data));
}
Collapse
 
aminnairi profile image
Amin • Edited
data : String
data =
    "Rome:Jan 81.2,Feb 63.2,Mar 70.3,Apr 55.7,May 53.0,Jun 36.4,Jul 17.5,Aug 27.5,Sep 60.9,Oct 117.7,Nov 111.0,Dec 97.9"
        ++ "\n"
        ++ "London:Jan 48.0,Feb 38.9,Mar 39.9,Apr 42.2,May 47.3,Jun 52.1,Jul 59.5,Aug 57.2,Sep 55.4,Oct 62.0,Nov 59.0,Dec 52.9"
        ++ "\n"
        ++ "Paris:Jan 182.3,Feb 120.6,Mar 158.1,Apr 204.9,May 323.1,Jun 300.5,Jul 236.8,Aug 192.9,Sep 66.3,Oct 63.3,Nov 83.2,Dec 154.7"
        ++ "\n"
        ++ "NY:Jan 108.7,Feb 101.8,Mar 131.9,Apr 93.5,May 98.8,Jun 93.6,Jul 102.2,Aug 131.8,Sep 92.0,Oct 82.3,Nov 107.8,Dec 94.2"
        ++ "\n"
        ++ "Vancouver:Jan 145.7,Feb 121.4,Mar 102.3,Apr 69.2,May 55.8,Jun 47.1,Jul 31.3,Aug 37.0,Sep 59.6,Oct 116.3,Nov 154.6,Dec 171.5"
        ++ "\n"
        ++ "Sydney:Jan 103.4,Feb 111.0,Mar 131.3,Apr 129.7,May 123.0,Jun 129.2,Jul 102.8,Aug 80.3,Sep 69.3,Oct 82.6,Nov 81.4,Dec 78.2"
        ++ "\n"
        ++ "Bangkok:Jan 10.6,Feb 28.2,Mar 30.7,Apr 71.8,May 189.4,Jun 151.7,Jul 158.2,Aug 187.0,Sep 319.9,Oct 230.8,Nov 57.3,Dec 9.4"
        ++ "\n"
        ++ "Tokyo:Jan 49.9,Feb 71.5,Mar 106.4,Apr 129.2,May 144.0,Jun 176.0,Jul 135.6,Aug 148.5,Sep 216.4,Oct 194.1,Nov 95.6,Dec 54.4"
        ++ "\n"
        ++ "Beijing:Jan 3.9,Feb 4.7,Mar 8.2,Apr 18.4,May 33.0,Jun 78.1,Jul 224.3,Aug 170.0,Sep 58.4,Oct 18.0,Nov 9.3,Dec 2.7"
        ++ "\n"
        ++ "Lima:Jan 1.2,Feb 0.9,Mar 0.7,Apr 0.4,May 0.6,Jun 1.8,Jul 4.4,Aug 3.1,Sep 3.3,Oct 1.7,Nov 0.5,Dec 0.7"
data1 : String
data1 =
    "Rome:Jan 90.2,Feb 73.2,Mar 80.3,Apr 55.7,May 53.0,Jun 36.4,Jul 17.5,Aug 27.5,Sep 60.9,Oct 147.7,Nov 121.0,Dec 97.9"
        ++ "\n"
        ++ "London:Jan 58.0,Feb 38.9,Mar 49.9,Apr 42.2,May 67.3,Jun 52.1,Jul 59.5,Aug 77.2,Sep 55.4,Oct 62.0,Nov 69.0,Dec 52.9"
        ++ "\n"
        ++ "Paris:Jan 182.3,Feb 120.6,Mar 188.1,Apr 204.9,May 323.1,Jun 350.5,Jul 336.8,Aug 192.9,Sep 66.3,Oct 63.3,Nov 83.2,Dec 154.7"
        ++ "\n"
        ++ "NY:Jan 128.7,Feb 121.8,Mar 151.9,Apr 93.5,May 98.8,Jun 93.6,Jul 142.2,Aug 131.8,Sep 92.0,Oct 82.3,Nov 107.8,Dec 94.2"
        ++ "\n"
        ++ "Vancouver:Jan 155.7,Feb 121.4,Mar 132.3,Apr 69.2,May 85.8,Jun 47.1,Jul 31.3,Aug 37.0,Sep 69.6,Oct 116.3,Nov 154.6,Dec 171.5"
        ++ "\n"
        ++ "Sydney:Jan 123.4,Feb 111.0,Mar 151.3,Apr 129.7,May 123.0,Jun 159.2,Jul 102.8,Aug 90.3,Sep 69.3,Oct 82.6,Nov 81.4,Dec 78.2"
        ++ "\n"
        ++ "Bangkok:Jan 20.6,Feb 28.2,Mar 40.7,Apr 81.8,May 189.4,Jun 151.7,Jul 198.2,Aug 197.0,Sep 319.9,Oct 230.8,Nov 57.3,Dec 9.4"
        ++ "\n"
        ++ "Tokyo:Jan 59.9,Feb 81.5,Mar 106.4,Apr 139.2,May 144.0,Jun 186.0,Jul 155.6,Aug 148.5,Sep 216.4,Oct 194.1,Nov 95.6,Dec 54.4"
        ++ "\n"
        ++ "Beijing:Jan 13.9,Feb 14.7,Mar 18.2,Apr 18.4,May 43.0,Jun 88.1,Jul 224.3,Aug 170.0,Sep 58.4,Oct 38.0,Nov 19.3,Dec 2.7"
        ++ "\n"
        ++ "Lima:Jan 11.2,Feb 10.9,Mar 10.7,Apr 10.4,May 10.6,Jun 11.8,Jul 14.4,Aug 13.1,Sep 23.3,Oct 1.7,Nov 0.5,Dec 10.7"
Collapse
 
mushtaqasif profile image
mushtaqasif • Edited

JS Solution

const [mean, variance] = (() => {
    const calc = (town, data, type = false) => {
        return data.split('\n').reduce((result, row) => {
            let [city, rainfallData] = row.split(':');

            if (city != town) return result;

            let rainfallMonthlyData = rainfallData.split(',');

            let rainfallAmounts = [];

            let mean = rainfallMonthlyData.reduce((total, record) => {
                let rainfallAmount = parseFloat(record.split(' ')[1]);

                rainfallAmounts.push(rainfallAmount);

                return total + rainfallAmount;
            }, 0) / rainfallMonthlyData.length; 

            return !type ? mean : rainfallAmounts.reduce((total, rainfallAmount) => 
                total + Math.pow((rainfallAmount - mean), 2)
            , 0) / rainfallMonthlyData.length; 
        }, -1);
    };

    return [
        (town, data) => calc(town, data),
        (town, data) => calc(town, data, true)
    ];
})();

console.log(JSON.stringify({
    London: {
        mean: mean("London", data),
        variance: variance("London", data)
    },
    mean: {
        Rome: mean('Rome', data1),
        Beijing: mean('Beijing', data)
    },
    variance: {
        Beijing: variance('Beijing', data1),
        Lima: variance('Lima', data)
    }
}, undefined, 4));

output:

{
    "London": {
        "mean": 51.199999999999996,
        "variance": 57.428333333333335
    },
    "mean": {
        "Rome": 71.77499999999999,
        "Beijing": 52.416666666666664
    },
    "variance": {
        "Beijing": 4437.038055555556,
        "Lima": 1.5790972222222222
    }
}
Collapse
 
cipharius profile image
Valts Liepiņš

Solution in Haskell:

import Data.List (find)

calcMean :: [Double] -> Double
calcMean [] = -1
calcMean xs = (foldr (+) 0 xs) / (fromIntegral . length $ xs)

calcVar :: [Double] -> Double
calcVar [] = -1
calcVar xs = calcMean . fmap diff $ xs
  where diff x = (x - calcMean xs)^2

getValues :: String -> String -> [Double]
getValues town = maybe [] parse . find theTown . lines
  where
    theTown = (==town) . takeWhile (/=':')
    parse = fmap (read . takeWhile (/=',')) . tail . words

mean :: String -> String -> Double
mean town = calcMean . getValues town

variance :: String -> String -> Double
variance town = calcVar . getValues town