Tips

IT技術系Tips

新人女子プログラマの書いたコードを直すだけの簡単なお仕事です! ←やってみた(Python)〜Part3〜

f:id:kaerouka:20131213081901p:plain
画像の出典:paiza
https://paiza.jp/poh/ec-campaign

前回の続き

100点になった。

二分探索(bisect)使った。

ソース

# -*- coding:utf-8 -*-
import sys, bisect


#prices = ["4 3","8000","4000","9000","6000","3000","14000","10000"] #=>0, 14000, 10000
#prices = ["5 2", "4000", "3000", "1000", "2000", "5000", "10000", "3000"] #=>9000, 3000
#prices = ["4 1","1000","3000","7000","8000","10000"] #=>10000
#prices = ["10 2", "4311", "89", "2836", "9904760", "12435", "8437", "345", "4356", "43287", "9648", "8999", "43222"] #=>8782, 22083
prices = [x.rstrip() for x in sys.stdin]

N, D = [int(x) for x in prices[0].split(' ')]
m_s = [int(x) for x in prices[N+1:]]
prices = [int(x) for x in prices[1: D * -1]]
prices.sort()

for n in xrange(D):
    result = 0
    m = m_s[n]
    current_prices = [x for x in prices if x + prices[0] <= m]
    current_len = len(current_prices)
    for i, x in enumerate(current_prices[:-1]):
        # 二分探索
        j = bisect.bisect_left(current_prices, m-x, i+1)

        # j < current_len → m-xがmax(current_prices)を超えると、範囲外のindexが返されるため、その対処
        # current_pricesはソート済みなので、current_prices[i]はcurrent_prices[i-1]より必ず大きいため
        # 前回までの値(result値)との比較は必要ない。
        if j < current_len and current_prices[i] + current_prices[j] == m:
            result = m
            break
        # 一つ上のif文の条件を満たさず、j == i+1を満たす場合、current_prices[i] + current_prices[j] <= mを満たさなかったと判断
        elif j == i+1:
            continue
        else:
            # 1つ前。
            j -= 1
            total = current_prices[i] + current_prices[j]
            if result < total <= m:
                result = total
                if result == m:
                    break

    print result

相変わらず入力値の受け取りが汚いが、目を瞑る。
めんどいので動作確認用の入力値もそのまま。

結果

f:id:kaerouka:20131216015643p:plain
画像の出典:paiza
https://paiza.jp/poh/ec-campaign

オールクリア!

f:id:kaerouka:20131216015754p:plain
画像の出典:paiza
https://paiza.jp/poh/ec-campaign

kaeroukaさん、凄いコードですねっ!!私にはこんな効率のいいコード書けませんっ!

かわいい。
彼女にはちゃんと仕様を読むプログラマーになっていただきたいところです(しみじみ



実行速度だが、Case3で5秒弱かかっている。
最速の人が0.09秒とか鬼畜の所業。

ここまでのチューニングはわりと普通なやり方だと思うんだけど、これ以降はどうすんのかねぇ。
いい結果が出たらまた記事にしよう。


過去の記事
新人女子プログラマの書いたコードを直すだけの簡単なお仕事です! ←やってみた(Python) - Tips
新人女子プログラマの書いたコードを直すだけの簡単なお仕事です! ←やってみた(Python)〜Part2〜 - Tips

新人女子プログラマの書いたコードを直すだけの簡単なお仕事です! ←やってみた(Python)〜Part2〜

f:id:kaerouka:20131213081901p:plain
画像の出典:paiza
https://paiza.jp/poh/ec-campaign

前回までの流れ

適当にやってみたところ、遅すぎる上に見事にバグりまくってたという醜態を晒した。
真面目にソース読んでみた人ごめんなさい。
しかもソース汚すぎ。

改善した

今回は少しだけ改善してみた。
[100, 200, 250, 120]
こんなデータを真面目にループで回すと

In [42]: for i in [100, 200, 250, 120]:
   ....:     for j in [100, 200, 250, 120]:
   ....:         

こんな感じになるわけだけど
最初のiとjの組み合わせがi=100, j=100
さらに、i=100, j=200、i=100, j=250、i=100, j=120、i=200, j=100
と続くわけだけど、i=200, j=100の組み合わせって、i=100, j=200と同じだからいらないよねって考え。
ようは、j=i+1から始めようって事。
同じ商品を選んじゃいけないので、iは120の行わない。

# python 2.7.3
import sys

prices = [x.rstrip() for x in sys.stdin]

N, D = [int(x) for x in prices[0].split(' ')]
m_s = [int(x) for x in prices[N+1:]]
prices = [int(x) for x in prices[1: D * -1]]

for n in xrange(D):
    result = 0
    for i, x in enumerate(prices[:-1]):
        for y in prices[i+1:]:
            total = x + y
            if total <= m_s[n] and result < total:
                result = total
    print result

結果

f:id:kaerouka:20131215155758p:plain
画像の出典:paiza

お、Case1クリア
王大人「Case2で死亡確認」

f:id:kaerouka:20131215155807p:plain
画像の出典:paiza
https://paiza.jp/poh/ec-campaign

kaeroukaさん、、すごーい。

かわいい。
Case2、Case3とクリアしていったら、服も1枚ずつ減ってったりするんだろうか。


次回は2分探索でチューニング予定。
Case3もクリアできたら嬉しいけど、どうだろう。

前回
新人女子プログラマの書いたコードを直すだけの簡単なお仕事です! ←やってみた(Python) - Tips
続き
新人女子プログラマの書いたコードを直すだけの簡単なお仕事です! ←やってみた(Python)〜Part3〜 - Tips

新人女子プログラマの書いたコードを直すだけの簡単なお仕事です! ←やってみた(Python)

新人女子プログラマの...とは

f:id:kaerouka:20131213081901p:plain
画像の出典:paiza
https://paiza.jp/poh/ec-campaign

新人女子プログラマの書いたコードを直すだけの簡単なお仕事です!
ECサイト内の2つの異なる商品(値段は同じでも構わない)を購入し、その合計価格が指定の価格以内で最大になる組み合せを探してください。

だそうです。
いわゆるハッカソンってやつで、みんなでコード書いて実行速度やら可読性やら比べようぜって企画です。
新人女子プログラマという言葉で引っ掛けようって魂胆が見え見えですね。
はい、釣られました。

お仕事の詳細

は、やたら長いので↑のリンク先見てね。

とりあえず動くもの

新人女子プログラマ「納期に間に合わない…」

とか言ってるわけですよ。
チューニングは後回しにして、とりあえず動くものを作らないといけないよね。
遅くても動いてればクライアントへの進捗報告もやりやすい。
おじさんが面倒見てやろうじゃないの。

ソース(バグってるので読み飛ばし推奨)
# python 2.7.3
import sys, math

prices = [x.rstrip() for x in sys.stdin]

N, D = [int(x) for x in prices[0].split(' ')]
m_s = [int(x) for x in prices[N+1:]]
prices = [int(x) for x in prices[1: D * -1]]
results = [0] * D

for n in xrange(D):
    for x in prices:
        for y in prices:
            a = math.fabs(m_s[n] - (x + y))
            b = math.fabs(math.fabs(results[n]) - math.fabs(m_s[n]))
            if a < b:
                results[n] = x + y

for x in results:
    print(x)

※2013/12/13追記 仕様よく読んでなくて、結構バグってる事が発覚

単純に1個ずつ足してって、今まで1番近かった解答と比較し
今回の比較の方が正解に近ければ、解答を書き換えるって仕組み。
計算量はO(D*N^2)かな。
どんだけmath.fabs呼んでんだよ。








結果は・・・・



























f:id:kaerouka:20131213072743p:plain
画像の出典:paiza

うおぉおおおい!タイムオーバー!?
15秒以内なんて要件あったんかい。

f:id:kaerouka:20131213074000p:plain
画像の出典:paiza

kaeroukaさん、ある意味凄いコードですね。
新人の私でもそうそうこんなコードかけませんよ。。

この女殺すわ。

続きは後日。

2013/12/13追記
CASE2のサンプルで動かしてみたら、正解と合わない。
よくよく問題見てみたら、2つの異なる商品と書いてあった罠。
さらに設定金額以下でって書いてあるから、math.fabsとかなんの関係も・・・
さて、そろそろ真面目にやらないと・・・
明日から本気出す!

続き↓
新人女子プログラマの書いたコードを直すだけの簡単なお仕事です! ←やってみた(Python)〜Part2〜 - Tips
新人女子プログラマの書いたコードを直すだけの簡単なお仕事です! ←やってみた(Python)〜Part3〜 - Tips

複数行を1行にまとめる、1行を複数行にばらす(PostgreSQL)

1行にまとめる

select array_to_string(array(select id from t01_articles where parent_id = '19343206'), ',')

カンマで結合している。

複数行にばらす

select regexp_split_to_table('東京,埼玉,奈良', ',')

カンマでsplitしている。

ファイルを読み込んで重複を削除する(Linux)

コマンド

(py3k)anonymous-no-MacBook-Pro:tmp anonymous$ cat yakuman.txt | sort | uniq
地和
天和
四暗刻
大三元
大四喜
字一色
小四喜
清老頭
緑一色
大三元 四暗刻
大三元 字一色
大四喜 字一色
小四喜 字一色
九蓮宝燈
国士無双
数え役満
四暗刻単騎
国士無双13面

uniqコマンドはソート済みのデータの重複を削除するコマンドなので、sortコマンドで一旦ソートしている。

yakuman.txt

四暗刻単騎
国士無双
大三元
国士無双
国士無双
小四喜
小四喜
大三元
....以下略

複数端末にpingする(Python3)

隣の人のPC上で動いてるVMに乗り込んで作業するはずだったんだけど
IP変わったらしく、繋がらない。
だいたい範囲わかってるから乱れ打ち。

ちょっと無理する

ソース

In [1]: import os, subprocess

In [2]: [x + ":" + str(subprocess.call(["ping", "-c", "1", "-t", "1", x], stdout=open(os.devnull,"w"))) for x in ["192.168.111." + str(y) for y in range(50,55)]]
Out[6]: 
['192.168.111.50:0',
 '192.168.111.51:2',
 '192.168.111.52:2',
 '192.168.111.53:2',
 '192.168.111.54:2']

わけわからん。

普通に書いた

ソース

import os
import subprocess

# 192.168.111.50 〜 192.168.111.54のリストを作成
L = ["192.168.111." + str(x) for x in range(50, 55)]
result = []
for ip in L:
    # pingを打って結果(ステータスコード)をipと共にリストに格納
    # 標準出力を/dev/nullへ、pingの回数は1回、タイムアウト1秒
    #引数の都合上、Linux系じゃないと動かない
    r = subprocess.call(["ping", "-c", "1", "-t", "1", ip], stdout=open(os.devnull, "w"))
    result.append("%s:%d" % (ip, r))

#表示
[print(x) for x in result]

結果

192.168.111.50:0
192.168.111.51:2
192.168.111.52:2
192.168.111.53:2
192.168.111.54:2

遅い。最悪ping数*1秒かかる。
fpingコマンド使えばわざわざこんなことしn・・・