CodeIQの「コード美人」に挑戦してみた

腕試しというよりも打ちのめされてることのほうが多いCodeIQでまた挑戦してみました。

提出内容

3のn乗と加算でピンときて、シンプルに解いてみました。目指せスリム系。
シンプルイズベストでは?ということで。


上のJavaScriptが提出内容で、下のは解説記事見た後にPowerShellで解いてみたオマケ。


出題者の方からフィードバックでコメントいただきました。

■Ozyよりひとこと
私が解答例として書いたコードも同じでした。
やっぱりコレですよねI

コレですよね!

フィードバックと解説記事までみて思ったこと

アルゴリズムの部分。今回たまたま私は王道を選んでましたが、他にも様々な考え方、解き方がありすぎてビックリしました。

プログラミング言語、JavaScript6名で比較的少数派…。
Rubyのシンプルなソースも見て勉強したくなりましたが、JavaScriptと頭の中ごっちゃになりそうです。

頭の回転早くする練習と考えて、これからも打ちのめされても挑戦し続けます。

CodeIQのジェムストリング問題をPowerShellで解いてみた

結城浩さんがCodeIQで出題したジェムストリング問題
限られた時間の中で解いて期限ギリギリに提出したのですが、使い慣れたJavaでかつマシンパワーに任せるという力技になってしまいました。
解答・解説を読み、高速化・省力化の手法を改めて学びなおしました。


というわけで、2月中ごろから本格的に手を付けてこれから習得しようとしているPowerShellで、改めてジェムストリング問題を解いてみました。
PowerShellで挑戦されている方は解答pdfの中には記載なかったかと思いますので初!かもしれません。

コード

まだPowerShell初心者丸出しですが生暖かい目でご覧下さい。

# Get-GemDays.ps1 ジェムストリング問題の計算
# usage
# > Set-ExecutionPolicy -Scope CurrentUser Unrestricted
# > .\Get-GemDays.ps1
#

# 対象宝石パターンを発見したか
$foundTarget = $false
# メモ化の実施有無($true or $false)
$memoized = $true
#$memoized = $false
# 宝石メモ
$memo = @{}

function Get-GemDays($gems, $target, $depth=0, $prevmatch=$false, $gemKeys=$null) {
  $days = 0
  $match = $false

  if (!$gemKeys) {
    $gemKeys = $gems.Keys | %{$_} | sort
  }

  # アルファベット順に宝石の組合せ計算
  $gemKeys | %{
    if (!$match) {
      $gems.$_--

      # メモ化のキー(配列だとうまくいかなかったので文字列)
      $gemMemoKey = $gems.Values | %{$_} | sort
      $gemMemoKey = $gemMemoKey -join ","
      
      if ($gems.$_ -ge 0) {
        $days++
        
        # 対象宝石パターンと一致確認
        $match = ($depth -eq 0 -or $prevmatch) -and $target[$depth] -eq $_

        # 対象宝石パターンと完全一致した場合、以後の処理を行わない
        if ($match -and $depth -eq ($target.Length-1)) {
          $foundTarget = $true
        }
        if (!$foundTarget) {
          if (!$match -and $memo.Keys -contains $gemMemoKey -and $memoized) {
#            Write-Host "Memo-Hit:" $gemMemoKey $memo[$gemMemoKey]
            $days += $memo[$gemMemoKey]
          
          } else {
            $tmpdays = Get-GemDays $gems $target ($depth+1) $match $gemKeys
            $days += $tmpdays
            if (!$match -and $memoized) {
              $memo[$gemMemoKey] = $tmpdays
#              Write-Host "Memo-in:" $gemMemoKey $tmpdays
            }
          }
        }
      }
      $gems.$_++
    }
  }

#  Write-Host "gems:" $gems.Values
#  Write-Host "days:" $days
  return $days
}

# "aaabcc" -> @{a=3;b=1;c=2}
function Hash-Gems($gemstr) {
  $hashgems =@{};
  $gemstr -split "" | %{if($_ -ne ""){$hashgems[$_]++}}
  return $hashgems
}

Measure-Command {
#  $days = Get-GemDays (Hash-Gems "aaabcc") ""
  $days = Get-GemDays (Hash-Gems "abbbbcddddeefggg") "eagcdfbe"
}
Write-Host "days:" $days

実行結果

メモ化有りの場合

約2秒。

> .\Get-GemDays.ps1

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 2
Milliseconds      : 148
Ticks             : 21489916
TotalDays         : 2.4872587962963E-05
TotalHours        : 0.000596942111111111
TotalMinutes      : 0.0358165266666667
TotalSeconds      : 2.1489916
TotalMilliseconds : 2148.9916

days: 5578864439
メモ化無しの場合
# メモ化の実施有無($true or $false)
#$memoized = $true
$memoized = $false

に変えて実行。

・・・1時間経ちましたが終わる気配がありません。

気になること

break/continueの動作

for-each内で再帰呼出を行っているが、for-each内にbreakやcontinueを入れたら再帰呼出自体が終了してしまった。
ひとまずはif文のネストで回避したものの、動きが怪しいので余裕があれば調べてみます。

Where-Objectの扱い

連想配列で、値が1以上のキー取り出し」がWhere-Objectを使ってできないか、気になったので後から調べてみました。

> $a = @{a=3;b=1;c=2;d=0;e=0;f=1}
> $a.Keys | Where-Object {$a.$_ -gt 0}

a
f
b
c

どうもキー定義順にはならないようで、アルファベット順にするためにsortしています。

コードゴルフに初挑戦してみた (お正月版 各桁総和ダンジョン LV1-3)

コードゴルフ
言葉とその意味を知ったのは恐らく5年ほど前だったと思います。
ある目的を達成するための最短コードを競うもので、その魔術的なコードを見て、ただただ呆然とした覚えがあります。

そして2014年。
CodeIQというサービスに登録し、その中にコードゴルフの問題がありました。

今までは魔法の使えない「戦士」のような存在でしたが、この問題に挑戦することで「魔法使い見習い」くらいにはなれるかな?と思い、挑戦してみました。

問題

● 各桁総和の魔法

 1から9999まで順に整数が与えられますので、以下の計算結果になる値を求めて、戻してください。
・数値を1桁ずつばらばらにして、和を求める。
・その和が1桁にならなかった場合は、同じ操作を続けて、1桁になるまで計算を行う。
例)
123 → 1+2+3 → 6 を戻す
9876 → 9+8+7+6 → 30 → 3+0 → 3 を戻す

● コード入力
function yourCode() {
    var arr = [];
    for (var i = 1; i <= 9999; i ++) {
        arr.push(???);
    }
    return arr;
}

LV1

挑戦者求む!【JavaScript】お正月版 各桁総和ダンジョン LV1 by クロノス・クラウン合同会社 柳井 政和│CodeIQ

入力欄の文字数:175文字以内
禁止文字:なし

制限無し。
先人の知恵をお借りして最短コードでいけました!

6文字

i%9||9

剰余1-8はTrue扱い→1-8
剰余0の場合はFalse扱い→9、になります。

LV2

挑戦者求む!【JavaScript】お正月版 各桁総和ダンジョン LV2 by クロノス・クラウン合同会社 柳井 政和│CodeIQ

入力欄の文字数:50文字以内
禁止文字:1 2 3 4 5 6 7 8 9

0が禁止されてないのがポイント、ということで「0xA-!0」→「10-1」で9を作りました。

18文字

(i-!0)%(0xa-!0)+!0

LV3

挑戦者求む!【JavaScript】お正月版 各桁総和ダンジョン LV3 by クロノス・クラウン合同会社 柳井 政和│CodeIQ

入力欄の文字数:100文字以内
禁止文字:1 2 3 4 5 6 7 8 9 0 , + % ? : this eval function Function Array join split repeat ' "

制限つきすぎて2晩くらい解けず眠れない日々を過ごしましたが。
「String(undefined).length」 →9という力技で解きました。70文字とか全然ゴルフじゃないです。

70文字

i-(i/String(undefined).length|!i)*String(undefined).length||String(undefined).length

最短コードの黒魔術っぷりに期待してます。

2/5追記

魔法使いの方からリプ頂きました!

Java Webアプリケーション+jQuery DataTables 1.9.4のbStateSave=trueでCookieに状態保存できない

はまったのでメモ。

事象

Tomcatで動作するJava Webアプリケーション上でjQuery DataTablesを使用しています。
DataTablesでは前回表示した状態を保持する機能がある(以下参照)のですが、Java Webアプリケーションの中で使うと状態保持できず、常に初期状態の表示になってしまいます。
DataTables example

原因

jQuery DataTablesが生成するCookieのキーの一部に「;jsessionid=xxx」が入ってしまうため、保存に失敗する。

対処

jquery_datatables.jsの以下の部分を修正すると正常動作する。

1. _fnCreateCookie

変更前

			/*
			 * Shocking but true - it would appear IE has major issues with having the path not having
			 * a trailing slash on it. We need the cookie to be available based on the path, so we
			 * have to append the file name to the cookie name. Appalling. Thanks to vex for adding the
			 * patch to use at least some of the path
			 */
			var aParts = window.location.pathname.split('/');
			var sNameFile = sName + '_' + aParts.pop().replace(/[\/:]/g,"").toLowerCase();
			var sFullCookie, oData;

			if ( fnCallback !== null )

変更後

		        /*
			 * Shocking but true - it would appear IE has major issues with having the path not having
			 * a trailing slash on it. We need the cookie to be available based on the path, so we
			 * have to append the file name to the cookie name. Appalling. Thanks to vex for adding the
			 * patch to use at least some of the path
			 */
			var aParts = window.location.pathname.split('/');
			var sNameFile = sName + '_' + aParts.pop().replace(/[\/:]/g,"").toLowerCase();
			var sFullCookie, oData;

			/*
			 * Need to remove anything after a semicolon so that the cookie doesn't contain one.
			 * This occurs when jsessionid is appended to the url for example.
			 */
			sNameFile = sNameFile.split(';', 1)[0];

			if ( fnCallback !== null )

2._fnReadCookie

変更前

			var
				aParts = window.location.pathname.split('/'),
				sNameEQ = sName + '_' + aParts[aParts.length-1].replace(/[\/:]/g,"").toLowerCase() + '=',
			 	sCookieContents = document.cookie.split(';');

変更後

			var
				aParts = window.location.pathname.split('/'),
				sNameEQ = sName + '_' + aParts[aParts.length-1].replace(/[\/:]/g,"").toLowerCase().split(';', 1)[0] + '=',
			 	sCookieContents = document.cookie.split(';');

OracleDBでINSERT/DELETEエラーのテスト

DBエラーが発生した時のアプリの振る舞いをテストするときにDB側に細工して意図的にエラーを発生させることをやりますが、その一つの方法です。
単体テストの度に毎回調べてて、毎回見つからなくて困るのでメモ。
INSERT/DELETE限定ですが、INDEXをUNUSABLEにしてテストしてます。UPDATEの場合はこの方法だとできないので、個別対処してます。

事前準備

SQL>alter table tbl1 move;
表が変更されました。

SQL> select index_name,status from user_indexes where index_name = 'IDX1';

STATUSがUNUSABLEになっていることを確認。

エラー確認

SQL>DELETE FROM tbl1 where col1=1;
ORA-01502: 索引'XXX.IDX1'またはそのパーティションが使用不可の状態です。

DELETEでエラーが発生することを確認。

事後のお片付け

SQL>alter index idx1 rebuild;
索引が変更されました。

SQL> select index_name,status from user_indexes where index_name = 'IDX1';

STATUSがVALIDになっていることを確認。

jmeterからWeb接続する際のプロキシサーバ設定

最近ちょこちょこ触るようになったjmeter
社内のHTTPプロキシサーバがあり、jmeter経由で社外のWebページにアクセスするとアクセスエラーとなってしまったため、jmeterのプロキシサーバの設定方法を調べることになりました。

jmeter自体にもプロキシサーバの機能があるためキーワード検索では調査難航しましたが、マニュアルの中から該当箇所を見つけました。

-H [proxy server hostname or ip address]
-P [proxy server port]
-N [nonproxy hosts] (e.g. *.apache.org|localhost)
-u [username for proxy authentication - if required]
-a [password for proxy authentication - if required]
Example : jmeter -H my.proxy.server -P 8000 -u username -a password -N localhost

Apache JMeter - User's Manual: Getting Started

Windows環境で動かしていたので、Exampleにあるような内容のバッチファイルを作って解決。

ORA-24816の対処。

今日、初めて見た。事象と対処法だけメモ。

事象

BLOB列とVARCHAR2(4000)列を持つAテーブルに、それぞれ最大サイズのデータをINSERTしようとしたところ、ORA-24816発生。

ORA-24816: 実際のLONGまたはLOB列の後に、指定されたLONG以外のバインド・データが拡張されました

閾値は見てないけど、こんな感じで事象再現。
・BLOB列:8000バイト、VARCHAR2(4000)列:4000バイトだと再現
・BLOB列:1000バイト、VARCHAR2(4000)列:4000バイトだと再現しない
・BLOB列:8000バイト、VARCHAR2(4000)列:1000バイトだと再現しない

対処法

回避方法は、INSERT、UPDATEのカラム順をLOB型を最後に配置するようにすると成功したと書かれていました。
とりあえず検証したところ、問題なく登録できましたしました。。

#ORA-24816
 insert into TABLE01(data2, title, data1, id)values(?, ?, ?, ?)
#成功
 insert into TABLE01(id, title, data1, data2)values(?, ?, ?, ?)
(UPDATEも同様に成功)

Oracle Technology Network (OTN) Japan - 掲示板 : ORA-24816: ...

ホントかよ、と疑いながらBLOB列を後ろにしたら解決。
S2JDBCの制約上、一番後ろにはできなかったけどVARCHAR2(4000)列の後ろにしたら再現しなかったので解決ってことで。