1
4

More than 3 years have passed since last update.

ゼロから始めるcodewars kata  lambdaを使って関数を戻り値に?!

Last updated at Posted at 2019-11-22

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はまだ難しい。。。

1
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
4