umegusa's blog

備忘録

エンジニアでもソースコード

先日のエンジニアでも恋がしたい(オンラインハッカソン)のソースコードとその解説を書きます。

オンラインハッカソンの概要


マンガ版「エンジニアでも恋がしたい!」〜転職初日にぶつかった女の子が同僚だった件〜|paizaオンラインハッカソン4 Lite

問題は全3問です。
今回はRubyで挑戦しましたがアルゴリズムが同じものなら他の言語でも書けると思います。

ソースコード

第一問目

在庫数の合計を出力する問題。
問題をそのまま実装すればOK。
1行目には対象の個数が入っているので、
その回数分ループを回して入力値を計算して出力します。

input_lines = gets
result = 0
(0..input_lines.to_i - 1).each do |i|
  result += gets.to_i
end
puts result

第二問目

最低限必要な在庫を補充するための金額を計算する問題。
在庫が足りなければ足りない分補充する金額を計算して、その合計を出力すればOK。

input_lines = gets
result = 0
(0..input_lines.to_i - 1).each do |i|
  # 入力値取得
  lines = gets.split("\s")
  # 必要な在庫
  targetStock = lines[0].to_i
  # 今ある在庫
  currentStock = lines[1].to_i
  # 値段
  productPrice = lines[2].to_i
  # 必要経費
  result += (targetStock - currentStock > 0 ? (targetStock - currentStock) * productPrice : 0)
end
puts result

第三問目

区間内の合計の最大値を求める問題。
AOJやってたときに似たような問題やったなーとか思いつつ解きました。
この問題は何も考えずに解くと計算量がO(n^2)になってタイムアウトします。

input_lines = gets
lines = input_lines.split("\s")
# ダメージ有効範囲
damageScope = lines[0].to_i
# 最大範囲
maxLength = lines[1].to_i
inputDamage = []
(0..maxLength - 1).each do |i|
  inputDamage << gets.to_i
end

# 最大ダメージ
maxDamage = 0
# 現在のダメージ
currentDamage = 0
if maxLength == damageScope
  # 範囲が同じ場合は全ての合計
  (0..inputDamage.length - 1).each do |i|
    maxDamage += inputDamage[i]
  end
else
  (0..maxLength - damageScope).each do |i|
    currentDamage = 0
    # ダメージ計算
    (i..damageScope + i - 1).each do |j|
      currentDamage += inputDamage[j]
    end

    # max値取得
    if currentDamage > maxDamage
      maxDamage = currentDamage
    end
  end
end
puts maxDamage

しかし、累積和というアルゴリズムを使用することで、計算量をがっつりさげられます。(O(n^2) -> O(nm))

input_lines = gets
lines = input_lines.split("\s")
# ダメージ有効範囲
damageScope = lines[0].to_i
# 最大範囲
maxLength = lines[1].to_i
# ダメージ取得
inputDamage = []
(0..maxLength - 1).each do |i|
  inputDamage << gets.to_i
end

# 最大ダメージ
maxDamage = 0
# 現在のダメージ
currentDamage = 0
if maxLength == damageScope
  # 範囲が同じ場合は全ての合計
  (0..inputDamage.length - 1).each do |i|
    maxDamage += inputDamage[i]
  end
else
  # 累積和の実装
  inputDamageSum = []
  # 0だけ計算する
  damageSum = 0
  (0..damageScope - 1).each do |i|
    damageSum += inputDamage[i]
  end
  inputDamageSum << damageSum

  # 数列の作成
  current = 0
  # 数列つくって読み込めばO(nm)でできる
  (damageScope..maxLength - 1).each do |i|
    inputDamageSum << inputDamageSum[current] - inputDamage[current] + inputDamage[i]
    current += 1
  end

  # 配列の最大値取得
  maxDamage = inputDamageSum.max
end
puts maxDamage

累積和は連続した数値を足していってできる配列のことです。
例えば、以下のような配列があるとします。

hoge = [1,2,3,4,5,6]

この配列の累積和は

fuga = [1,3,6,10,15,21]

となります。(1, 1+2, 1+2+3, 1+2+3+4,....)

で、この累積和を使うと区間の合計を簡単に出すことができます。
例えば、3~5番目の合計を求めたい場合
5番目の合計数値から2番目の数値を引いた値がその合計値になります。(3 + 4 + 5 = 12 => 15 - 3 = 12)

連続した値の数列をa、累積和の数列をbとすると、下記のような式になります。

a[l] + a[l+1] + a[l+2] + ... + a[r] = b[r] - b[l - 1]
result = b[r] - b[l - 1]

この考え方を用いたプログラムを書くと上記のようになります。

おわりに

累積和とかちゃんと書いてますけど実はこんな名前あるとは知らずに解いていたり・・・
昔似たようなプログラム書いたなーってことで調べてたらちゃんと名前があってそれできれいにした感じです。

でも多分他にも有効なアルゴリズムとかあるんじゃないかなと予想しているので、機会があればみなさんも解いてみてはいかがでしょう!

エンジニアでも恋がしたい!に挑戦しました

エンジニアでも恋がしたい!

お久しぶりです。
Swiftとかいろいろ遊んでるうちに年末になっちゃいました。
年末と言えばちらっと見つけたのですがこちら
マンガ版「エンジニアでも恋がしたい!」〜転職初日にぶつかった女の子が同僚だった件〜|paizaオンラインハッカソン4 Lite

いつだか似たようなものに挑戦しましたね。
こちら
オンラインハッカソンなるものに挑戦 - umegusa's blog
よく見ると同じ登場人物だった。

小休止ということでこちらに挑戦。
結果は全問完答してALL100点でした!やったね!

1回で全完ではなかったのですが、いろいろ試してなんとかできました。
まだ開催期間ということなので、コードは終了後にさらします。
今回もRubyで書きました。

そんなに難しくなかったので皆さんも挑戦してみてはいかがでしょうか!
と言うことで生存報告を兼ねた更新でした。

SwiftでNSURLConnectionを使ってHTMLを取得

Swift使ってHTML取得してみました。
Objective-Cに比べてすげー楽にすらすら書ける気がする。。。

NSURLConnectionを使用して非同期通信

NSURLConnectionに用意されているプロトコルを使って実装します。

    // サーバからレスポンスを受け取ったときのデリゲート
    func connection(didReceiveResponse: NSURLConnection!, didReceiveResponse response: NSURLResponse!) {
    }
    
    // サーバからデータが送られてきたときのデリゲート
    func connection(connection: NSURLConnection!, didReceiveData data: NSData!){
    }
    
    // データロードが完了したときのデリゲート
    func connectionDidFinishLoading(connection: NSURLConnection!){
    }

これらのメソッドを実装するだけです。
Objective-Cとなんら変わらない。

ソースコードの全貌

ということで今回書いたコードは以下のとおり。
単純にURL指定してURLをコンソールに出力。
画面にはsuccessと表示するだけです。

ViewController.swift

import UIKit


class ViewController: UIViewController, ConnectionResult {
    // プロトコルを継承する
    
    // !マークは値が必ず入っていることが保証されるOptional型
    // 値が入っていないとエラーになる
    // この場合はStroyboardからひもづけているので必ずついていなければならない
    // reference outlet@storyboard
    @IBOutlet var label: UILabel!
    var connection : Connection!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    // touch up inside@storyboard
    @IBAction func btnClick(sender: AnyObject) {
        // インスタンス化とデリゲートのセット
        connection = Connection(urlStr: "ここにURL")
        connection.delegate = self
        connection.doConnect()
    }
    
    // delegate
    // 実際に処理を行う
    func showResult(resultMessage: String?) -> Void {
        label.text = resultMessage
    }
}

Connection.swift

import Foundation

// プロトコル
protocol ConnectionResult{
    func showResult(resultMessage: String?) -> Void
}

public class Connection : NSObject{
    
    // 参考: 
    // NSURLConnection ttp://stackoverflow.com/questions/24176362/ios-swift-and-nsurlconnection
    // Delegate, Protocol ttp://qiita.com/mochizukikotaro/items/a5bc60d92aa2d6fe52ca
    
    // nilが入ってるなんてあり得ない!
    var urlStr : String
    var data : NSMutableData? = nil
    var delegate : ConnectionResult!
    
    // コンストラクタ
    public init(urlStr: String) {
        self.data = NSMutableData()
        self.urlStr = urlStr
    }
    
    // アクセス
    public func doConnect() -> Void{
        var url : NSURL = NSURL(string: urlStr)
        // キャッシュを無視
        var request : NSURLRequest = NSURLRequest(URL: url, cachePolicy:NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData, timeoutInterval: 60.0)
        
        var connect : NSURLConnection = NSURLConnection(request: request, delegate: self, startImmediately: true)
        // 接続開始
        connect.start()
    }
    
    // サーバからレスポンスを受け取ったときのデリゲート
    func connection(didReceiveResponse: NSURLConnection!, didReceiveResponse response: NSURLResponse!) {
        // Recieved a new request, clear out the data object
        self.data! = NSMutableData()
    }
    
    // サーバからデータが送られてきたときのデリゲート
    func connection(connection: NSURLConnection!, didReceiveData data: NSData!){
        self.data!.appendData(data)
    }
    
    // データロードが完了したときのデリゲート
    func connectionDidFinishLoading(connection: NSURLConnection!){
        // バイナリデータが発行される
        let html : String = NSString(data: self.data!, encoding: NSUTF8StringEncoding)
        // コンソールに出力
        println(html)
        
        // 処理を呼び出すだけ
        self.delegate.showResult("success!")
    }
}

DelegateとProtocolとを独自に実装。
これらについても忘れそうなのでそのうち残しておこう。
アクセス修飾子についての理解も甘い、CocoaとかFoundationとかは全publicじゃないとだめなのかな?
デリゲートメソッドprivateで定義したらだめだった。

githubにもあげました。
https://github.com/kaisou4537/swiftstudy/tree/master/swift_4/ConnectionTest

Swift面白い

全文英語だけど何とか読めるドキュメント。
まだiOSアプリ開発事態に慣れないので本読みながらサンプルアプリガッつりつくっていこう。

とはいってもモダンなプログラミング言語と言うだけあって「こう書けば動きそう」って書いたら割と動いちゃったりする。

やっていて楽しいのは久しぶりな感じ。
まだ新しいと言うのもあるけれども。。。

CSVの内容をDBに登録するクエリ

小休止。
タブ区切りのcsvの内容をDBに登録するクエリを吐きだすスクリプト作成。

https://gist.github.com/kaisou4537/37b9cb0ce28aabec08fb

# 今回は使わない
columns = []
# データ格納
datas = []
first = true
File::open('sample.txt','r') do |f|
	while line = f.gets
		strs = line.strip.split("\t")
		data = []
		strs.each do |str|
			if first then
				columns << str
			else
				data << str
			end
 
		if !first then
			datas << data
		end
 
		end
		first = false
	end
end
 
puts columns
puts datas
 
query = "Insert into T_hoge Values\n"
 
first = true
datas.each do |data|
	add_query = ""
	if first then
		add_query = "("
			first = false
	else
		add_query = ",("
	end
 
	query_first = true
	data.each do |str|
		if query_first then
			add_query += "'#{str.strip}'"
			query_first = false
		else
			add_query += ",'#{str.strip}'"
		end
	end
 
	add_query += ")"
	query += add_query + "\n"
end
 
puts query

TextUtilみたいなのあったら教えてほしい。。。

github for windowsで詰まったのでメモ

github for windowsを入れてみたんですが、System.Deployment.Application.DeploymentDownloadExceptionというエラーに当たってインストールができなかったのでメモ。
あとは少し使い方とか

github for windowsをインストール

http://windows.github.com/
ここからインストーラをダウンロードしてインストール。
普通にインストールすると上記のエラーに引っかかるんだけど、
管理者として実行したらすんなりインストールできました。

原因は後で調べてみよう。。。

github for windowsからコミット

github for windowsをインストールすると一緒にgit shellもインストールされます。
自分はコンソールで操作したほうが楽なのでこっちを使います。
git shellはpower shellらしいです。

github for windowsを起動するとまず自分の登録情報を入力することで使用できるようになります。

リポジトリの追加などはフォルダをドラッグアンドドロップするだけで追加できるので楽でした。

その後git shellを立ち上げてリポジトリを追加したフォルダまで移動、その後githubに書いてあるコマンドを実行すれば終了です。

git init
git add .
git commit -m "message"
git remote add origin git@github.com:hogehoge/hoge.git
git push -u origin master

これだけ

最後に

gitをwindowsに入れたりとかしなくても全部入れてくれるんですね、これは大分楽です。

FragmentのViewをいじってみる

タブで動かせるようになったんでFragment部分のViewをいじってみます

ActivityとFragment

Javaxmlファイルはこんな感じになりました。

activity_main.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.app.MainActivity"
    tools:ignore="MergeRootFrame" />

fragment_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context="com.example.app.MainActivity$PlaceholderFragment">

<TextView
    android:text="tab1 test"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/textView" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="New Button"
        android:id="@+id/test_button"
        android:layout_below="@+id/textView"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/test_textfield"
        android:layout_below="@+id/test_button"
        android:layout_toRightOf="@+id/textView"
        android:layout_marginTop="61dp" />

</RelativeLayout>


MainActivity.Java

package com.example.app;

import android.app.ActionBar;
import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final ActionBar actionBar = getActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        actionBar.addTab(actionBar.newTab().setText("Tab1").setTabListener(
                new MainTabListener<MainFragmentView>(
                        this, "flag1", MainFragmentView.class
                )
        ));

        actionBar.addTab(actionBar.newTab().setText("Tab2").setTabListener(
                new MainTabListener<SubFragmentView>(
                        this, "flag2", SubFragmentView.class
                )
        ));

    }
}

MainFragment.Java

package com.example.app;

import android.os.Bundle;
import android.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;

public class MainFragmentView extends Fragment{

    private TextView textView;

    @Override
    public View onCreateView(
            LayoutInflater inflater,
            ViewGroup container,
            Bundle savedInstanceState){

        View view = inflater.inflate(R.layout.fragment_main, container, false);
        textView = (TextView)view.findViewById(R.id.test_textfield);
        textView.setText("text test");
        Button button = (Button)view.findViewById(R.id.test_button);
        button.setText("change text!");

        button.setOnClickListener(button1onClickListener);

        return view;
    }

    View.OnClickListener button1onClickListener = new View.OnClickListener(){
        @Override
        public void onClick(View v){
            changeShowText("button click now!");
        }
    };


    public void changeShowText(String str){
        textView.setText(str);
    }

}


こんな感じでactivity_mainの上にあるFragmentをいじれるようになりました。
ここまでこれれば後は中身の実装していけばかけーぼはできそうですね。

書き方ってかなり独自になっている気がするけどこれで問題ないのかな。。。
間違ってたら誰か教えてください。

とりあえず

ActivityとFragmentを分けてFragment部分でViewの操作をすることができました。
このままかけーぼの完成目指してがんばります。

補足

前回の分とあわせてgithubにコミットできましたので公開。
https://github.com/kaisou4537/Mo

Windowsgithubのクライアントを配ってたけどそこで詰まったこともあったのでそれは後で書きます。

【Android】ActionBarを使ってTabごとにViewを設定する

かけーぼ進みません!!
レイアウトだけ作ってみようと思ってとりあえずタブごとにビューを切り替える処理を書いたのでメモ。

Android Studioを使って書いてるけどいつの間にかプロジェクト新規作成時にできるファイルとか増えててびっくりです。

TabActivityが非推奨になってて他の方法を探していてFragmentとActionBarを使ったTab Navigationに行きついたわけです。
やり方としてはフラグメント上にタブ設置してそれぞれのビューを設置するみたいなイメージです。

Fragmentが実装されたのは3.xかららしく、最初にFragmentっていう土台を用意してその上にViewのパーツを並べていくみたいな
そんな感じでUIを設計していくみたいですね。

ソースコードはのちほど公開します。
実行画面はこんな感じ。

f:id:umegusa:20140324020801p:plain
f:id:umegusa:20140324020805p:plain

タブメニューを下にするにはどうすればいいのかな・・・。
とりあえず今日はここまで。