エンジニアでもソースコード
先日のエンジニアでも恋がしたい(オンラインハッカソン)のソースコードとその解説を書きます。
ソースコード
第一問目
在庫数の合計を出力する問題。
問題をそのまま実装すれば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
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
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
【Android】ActionBarを使ってTabごとにViewを設定する
かけーぼ進みません!!
レイアウトだけ作ってみようと思ってとりあえずタブごとにビューを切り替える処理を書いたのでメモ。
Android Studioを使って書いてるけどいつの間にかプロジェクト新規作成時にできるファイルとか増えててびっくりです。
TabActivityが非推奨になってて他の方法を探していてFragmentとActionBarを使ったTab Navigationに行きついたわけです。
やり方としてはフラグメント上にタブ設置してそれぞれのビューを設置するみたいなイメージです。
Fragmentが実装されたのは3.xかららしく、最初にFragmentっていう土台を用意してその上にViewのパーツを並べていくみたいな
そんな感じでUIを設計していくみたいですね。
ソースコードはのちほど公開します。
実行画面はこんな感じ。
タブメニューを下にするにはどうすればいいのかな・・・。
とりあえず今日はここまで。