codewars kata とは
一言で言うなら、プログラミングを鍛えられる道場です
海外版AtCoderと言ってもいいかもしれません
まあAtCoderは使い方がよく分からなかったのでやった事ないのですが
個人的にはAtCoderより肌に合いました
きっかけ
この記事を読んでじゃあやってみようと思い3日前くらいから始めました
19歳のソフトウェア開発者の女の子からのアドバイス
私は、1日に最低でも5つのCodeWars Kataを解くようにしています。CodeWarsは、コーディングを始めたばかりの時だけでなく、何年もコーディングを続けてきた時でも、あなたの親友です!CodeWarsが提供する問題の解法はいつもとても有益で、他の人が提供した解法をスクロールしていくだけで自分の構文を大きく改善することができます。もう1つの大きな利点は、コーディングの面接に行くと、多くの場合CodeWarsで出されるものとよく似た質問をされることがあるということです。
というわけで早速問題へ
とはいえ所詮自分用の記事なので
気になったらcodewars kataにアクセスするのをオススメ
問題1
Your goal in this kata is to implement a difference function, which subtracts one list from another and returns the result.
あるリストから別のリストの中身を引く関数を作ってちょ
It should remove all values from list a, which are present in list b.
リストbにある関数は全部引いてね
例)
array_diff([1,2],[1]) == [2]
If a value is present in b, all of its occurrences must be removed from the other:
bの数字が複数あったら全部引いてね
array_diff([1,2,2,2,3],[2]) == [1,3]
私の答え
def array_diff(a, b):
return [a1 for a1 in a if a1 not in b]
ちょっとスマートに答えられたんじゃないかな・・・?
さて、他の人の回答は・・・
Best Practice
def array_diff(a, b):
return [x for x in a if x not in b]
まったく一緒やん!!!
3日目にしてkataの書き方に慣れてきたかな
問題2
ダイヤモンドを作れ!!!!
図形見たまんま1,3,5,7・・・各サイズのダイヤモンドを作る関数を作るみたいですね
Jamie is a programmer, and James' girlfriend. She likes diamonds, and wants a diamond string from James. Since James doesn't know how to make this happen, he needs your help.
Task
You need to return a string that looks like a diamond shape when printed on the screen, using asterisk (*) characters. Trailing spaces should be removed, and every line must be terminated with a newline character (\n).
Return null/nil/None/... if the input is an even number or negative, as it is not possible to print a diamond of even or negative size.
Examples
A size 3 diamond:
*
***
*
...which would appear as a string of " *\n***\n *\n"
A size 5 diamond:
*
***
*****
***
*
...that is: " *\n ***\n*****\n ***\n *\n"
私の答え
def diamond(n):
# Make some diamonds!
if n%2 ==0 or n <1:
return None
ans=''
for i in range(1,n+1,2):
ans += '{}{}\n'.format(' '*((n-i)//2) ,'*'*i)
for i in range(n-2,0,-2):
ans += '{}{}\n'.format(' '*((n-i)//2) ,'*'*i)
return ans
コードはキレイではないけど出力がキレイすぎて満足しちゃいました
Best Practice
def diamond(n):
if n > 0 and n % 2 == 1:
diamond = ""
for i in range(n):
diamond += " " * abs((n/2) - i)
diamond += "*" * (n - abs((n-1) - 2 * i))
diamond += "\n"
return diamond
else:
return None
abs(n/2 - i)をうまく使って私がやったような場合分けを省いていますね、頭いい
あとは
def diamond(n):
if not n%2 or n<1: return None
d = [" "*i+"*"*(n-2*i)+"\n" for i in range(n/2,0,-1)]
return ''.join(d) + "*"*n + "\n" + ''.join(d[::-1])
半ダイヤモンドを作っておいて、上からなぞるか下からなぞるかで使い分けている
これも頭いい
問題3
You have an array of numbers.
文字列を与えます
Your task is to sort ascending odd numbers but even numbers must be on their places.
奇数だけソートしてね、偶数はそのままでいいよ
Zero isn't an odd number and you don't need to move it. If you have an empty array, you need to return it.
ゼロは偶数、空配列だったらreturnも空配列でね
Example
sort_array([5, 3, 2, 8, 1, 4]) == [1, 3, 2, 8, 5, 4]
私の答え
def sort_array(ar):
# Return a sorted array.
odd = sorted([a for a in ar if a%2 ==1])
even = [a for a in ar if a%2 ==0]
flg = [a%2 for a in ar]
ans = []
od = 0
ev = 0
for i in range(len(ar)):
if flg[i]:
ans.append(odd[od])
od +=1
if not flg[i]:
ans.append(even[ev])
ev+=1
return ans
いい方法が思いつかなかったので素直に奇数偶数分けて処理
Best Practice
def sort_array(arr):
odds = sorted((x for x in arr if x%2 != 0), reverse=True)
return [x if x%2==0 else odds.pop() for x in arr]
oddsを作った後for x in arr
で配列を再生成するのですが
x if x%2==0
は偶数処理で難しくはないかと
list.pop()は配列の最後の要素を取り出し&削除できる
list.pop(0)だと先頭の要素で同じことが出来る
else odds.pop()
するとodd配列の最後の要素を取り出し&削除でき
それをfor文の中に入れる事で小さい順に1ずつ見ると・・・頭いい
例
odds=[5,3,1]
print('get:',odds.pop(),',odd:',odds)
==> get: 1 ,odd: [5, 3]
問題 4
If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
10以下で、3,5の倍数をリストアップすると3,5,6,9で和は23
Finish the solution so that it returns the sum of all the multiples of 3 or 5 below the number passed in.
和を求めよ
Note: If the number is a multiple of both 3 and 5, only count it once.
Note:どっちもの倍数だったらカウントは1回
私の回答
def solution(number):
return sum([x for x in range(0,number,3)]+[x for x in range(0,number,5)]) - sum([x for x in range(0,number,15)])
一番シンプルな?3の倍数の和+5の倍数の和-15の倍数の和
Best Practice
def solution(number):
return sum(x for x in range(number) if x % 3 == 0 or x % 5 == 0)
3か5で割れる数の総和
これもシンプル
問題5
This time we want to write calculations using functions and get the results. Let's have a look at some examples:
計算するやつ作れ。例えば・・・こんなん ↓
seven(times(five())) # must return 35
four(plus(nine())) # must return 13
eight(minus(three())) # must return 5
six(divided_by(two())) # must return 3
Requirements:
There must be a function for each number from 0 ("zero") to 9 ("nine")
There must be a function for each of the following mathematical operations: plus, minus, times, dividedBy (divided_by in Ruby and Python)
Each calculation consist of exactly one operation and two numbers
The most outer function represents the left operand, the most inner function represents the right operand
Divison should be integer division. For example, this should return 2, not 2.666666...:
- 関数は0~9
- 足す引く割る掛けるして
- 計算は2個の数字と1つの演算子が必ずある
- 演算は外側の数字が左、内側が右
- 割り算は切り捨て
さて、7kyuの私が操作をミスっていつもより圧倒的に難しい5kyuの問題を選んでしまいました
回答は見るに堪えないゴリ押しコードですが。。。
あ、これは読む価値ないですよ
def zero(num = 0.5): #your code here
if num == 0.5:
return 0
return clac(0,num[0],num[1])
def one(num = 0.5): #your code here
if num == 0.5:
return 1
return clac(1,num[0],num[1])
def two(num =0.5): #your code here
if num == 0.5:
return 2
return clac(2,num[0],num[1])
def three(num = 0.5): #your code here
if num == 0.5:
return 3
return clac(3,num[0],num[1])
def four(num = 0.5): #your code here
if num == 0.5:
return 4
return clac(4,num[0],num[1])
def five(num = 0.5): #your code here
if num == 0.5:
return 5
return clac(5,num[0],num[1])
def six(num = 0.5): #your code here
if num == 0.5:
return 6
return clac(6,num[0],num[1])
def seven(num = 0.5): #your code here
if num == 0.5:
return 7
return clac(7,num[0],num[1])
def eight(num = 0.5): #your code here
if num == 0.5:
return 8
return clac(8,num[0],num[1])
def nine(num = 0.5): #your code here
if num == 0.5:
return 9
return clac(9,num[0],num[1])
def plus(num): #your code here
return [num,1]
def minus(num): #your code here
return [num,2]
def times(num): #your code here
return [num,3]
def divided_by(num): #your code here
return [num,4]
def clac(a,b,operation):
if operation ==1:
return a + b
if operation ==2:
return a - b
if operation ==3:
return a * b
if operation ==4:
return a // b
そしてベストプラクティスの回答がこれ
def zero(f = None): return 0 if not f else f(0)
def one(f = None): return 1 if not f else f(1)
def two(f = None): return 2 if not f else f(2)
def three(f = None): return 3 if not f else f(3)
def four(f = None): return 4 if not f else f(4)
def five(f = None): return 5 if not f else f(5)
def six(f = None): return 6 if not f else f(6)
def seven(f = None): return 7 if not f else f(7)
def eight(f = None): return 8 if not f else f(8)
def nine(f = None): return 9 if not f else f(9)
def plus(y): return lambda x: x+y
def minus(y): return lambda x: x-y
def times(y): return lambda x: x*y
def divided_by(y): return lambda x: x/y
・・・ ???
なんかかっこいい
読み解いていきます
def zero(f = None): return 0 if not f
ここまでは基本的で、私でも出来たはずの構造ですね、反省(クソコードを公開しているのが恥ずかしい)
else f(0)
・・・??? ナニコレ
これ、関数を引数に取ってるんですねえ~。
そんなことできるなんて知らなかった。しかも、lambdaを使って。
def plus(y): return lambda x: x+y
・・・どうやらキモはlambda
のよう
seven(times(five()))
を例にゆっくり見ていきます
まずseven(times(five()))
が
seven(times(5))
になります
次にtimes(5)
の戻り値がlambda x: x+y
なので
def f(x):
return x * 5
となる関数が返されます
そしてその関数に対してf(7)しているので戻り値は35
になるというわけですね
ここまで読み解くのにだいぶ時間がかかりました
やはり5kyuはまだ難しい。。。