1. 문제

www.codewars.com/kata/56a32dd6e4f4748cc3000006

 

Codewars: Achieve mastery through challenge

Codewars is where developers achieve code mastery through challenge. Train on kata in the dojo and reach your highest potential.

www.codewars.com

문제 설명

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:

data and towns can be seen in "Your Test Cases:".

Task:

  • function:mean(town, strng)should return the average of rainfall for the citytown and the strng data ordata1(In R and Julia this function is calledavg).
  • function:variance(town, strng) should return the variance of rainfall for the city town and the strng data or data1.

제한 사항

  • if functions mean or variance have as parameter town a city which has no records return -1 or -1.0 (depending on the language)

  • Don't truncate or round: the tests will pass if abs(your\_result - test\_result) <= 1e-2 or abs((your\_result - test\_result) / test\_result) <= 1e-6 depending on the language.

  • Shell tests only variance

  • A ref:http://www.mathsisfun.com/data/standard-deviation.html

  • data and data1(can be name d0 and d1 depending on the language; see "Sample Tests:") are adapted from:http://www.worldclimate.com

입출력 예

mean("London", data), 51.19(9999999999996)

variance("London", data), 57.42(833333333374)


2. 어떻게 풀까?

  • 우선 data\n으로 도시들이 구분되어 있고, 도시와 월별 rainfall은 :로 구분되어있다고 하니 data를 통해 각 도시와 rainfall을 split 하는 게 중요해 보인다.
  • 그 이후에는 각 rainfall들을 더해서 12로 나누어 평균값(mean)을 구하고, mean을 이용해서 variance도 구하면 되겠다.
  • mean은 평균값인게 이해가 갔는데 variance는 뭔지 몰랐다. 근데 참고 링크를 보니까 딱 알겠더라.
  • 제한 사항을 보니 입력의 towndata or data1에 존재하지 않으면 -1을 리턴하라고 한다.
    • 처음에는 입력으로 주어진 town에 대한 결과값만 리턴하면 되겠다. 생각했는데, 이 제한사항 때문에 Map을 이용해야겠다고 생각했다.

3. 코드

테스트 코드

package codeWars.kyu6.rainFall_20201117;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;

import org.junit.Test;

public class RainfallTest {

  public static 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";

  public static 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";

  @Test
  public void meanTest() {
    assertThat(Rainfall.mean("London", data), is(51.199999999999996));
    assertThat(Rainfall.mean("Beijing", data), is(52.416666666666664));
  }

  @Test
  public void varianceTest() {
    assertThat(Rainfall.variance("London", data), is(57.42833333333374));
    assertThat(Rainfall.variance("Beijing", data), is(4808.37138888889));
  }

  @Test
  public void whenDataHasNotTownTest() {
    assertThat(Rainfall.mean("Lon", data), is(-1.0));
    assertThat(Rainfall.variance("Lon", data), is(-1.0));
  }
}

실제 코드

package codeWars.kyu6.rainFall_20201117;

import java.util.HashMap;
import java.util.Map;

public class Rainfall {

  public static double mean(String town, String strng) {
    Map<String, Double> townRainfallMeanMap = buildTownRainfallMeanMap(strng);

    return townRainfallMeanMap.getOrDefault(town, -1.0);
  }

  private static Map<String, Double> buildTownRainfallMeanMap(String strng) {
    Map<String, Double> townRainfallMeanMap = new HashMap<>();
    String[] townAndMonthRainfalls = strng.split("\n");

    for (String townAndMonthRainfall : townAndMonthRainfalls) {
      String targetTown = townAndMonthRainfall.split(":")[0];
      String[] monthRainfalls = townAndMonthRainfall.split(":")[1].split(",");
      double sumOfRecords = 0;

      for (String monthRainfall : monthRainfalls) {
        sumOfRecords += Double.parseDouble(monthRainfall.split(" ")[1]);
      }
      townRainfallMeanMap.put(targetTown, sumOfRecords / 12);
    }

    return townRainfallMeanMap;
  }

  public static double variance(String town, String strng) {
    Map<String, Double> townRainfallVarianceMap = buildTownRainfallVarianceMap(town, strng);

    return townRainfallVarianceMap.getOrDefault(town, -1.0);
  }

  private static Map<String, Double> buildTownRainfallVarianceMap(String town, String strng) {
    Map<String, Double> townRainfallVarianceMap = new HashMap<>();
    double mean = mean(town, strng);
    String[] townAndMonthRainfalls = strng.split("\n");

    for (String townAndMonthRainfall : townAndMonthRainfalls) {
      String targetTown = townAndMonthRainfall.split(":")[0];
      String[] monthRainfalls = townAndMonthRainfall.split(":")[1].split(",");
      double sumOfRecords = 0;

      for (String monthRainfall : monthRainfalls) {
        double rainfall = Double.parseDouble(monthRainfall.split(" ")[1]);
        sumOfRecords += Math.pow((rainfall - mean), 2);
      }
      townRainfallVarianceMap.put(targetTown, sumOfRecords / 12);
    }

    return townRainfallVarianceMap;
  }
}

mean()variance() 둘 다 비슷하게 구현했다. data로 주어진 strng\n으로 쪼개 town별로 분리하고, 분리한 town String 배열에서 :으로 쪼개 도시와 월별 rainfall로 분리했다. 그리고 rainfall끼리 전부 더해서 12로 나누어준 값을 map에 저장했다. varinace()에서는 mean()을 이용하여 variance를 구했다.


4. 느낀점

  • 어렵지 않은 문제였다. String을 어떻게 잘 쪼개냐가 관건인 것 같다.

+ Recent posts