火曜日, 12月 02, 2014

貪欲なアルゴリズム

会社で誰かが貪欲なアルゴリズムの問題を出していたので,日本の硬貨単位に合わせたものを解いてみた.DPを使わなければまぁ大概はこのような解になるだろう.

#include <iostream>
#include <vector>
#include <utility>
#include <algorithm>

int coins[] = { 1, 5, 10, 50, 100, 500 };
int nums[] = { 6, 3, 4, 5, 3, 2 };

void useCoins(int amounts, std::vector<std::pair<int,int>*>& pV) {
 int num;
 for (int i = sizeof(coins) / sizeof(int) - 1; i >= 0; i--) {
  if (amounts <= 0) {
   return;
  }
  num = std::min(amounts / coins[i], nums[i]);
  amounts -= num * coins[i]; 
  pV.push_back(new std::pair<int,int>(coins[i], num));  
 }
}

int main() {
 std::vector<std::pair<int,int>*> v;
 useCoins(1280, v);
 for_each(v.begin(), v.end(), [](std::pair<int,int>* x){ std::cout << x->first << ":" << x->second << std::endl; });

}

水曜日, 9月 17, 2014

std::to_string

C++11以降では数値型から文字列に変換するのにstd::to_string()を使えばよい.これは便利である.以下は整数値を文字列に変換する例.

#include <iterator>
#include <iostream>
#include <list>
#include <algorithm>
#include <sstream>
#include <string>

int main() {
 std::list<int> v{ 25, 30, 10, 90, 500 };
 std::list<std::string> v2;
 std::transform(v.begin(), v.end(), std::back_inserter(v2), [](int x)->std::string { return std::to_string(x); });
 std::stringstream ss;
 std::for_each(v2.begin(), v2.end(), [&ss](std::string s)->void {ss << s << ","; });
 std::cout << ss.str().substr(0,ss.str().length()-1) << std::endl;
}


金曜日, 8月 22, 2014

std::future

JavaのFutureとほぼ同様の機能を持つ,std::futureがC++11では利用可能である.

#include <cmath>
#include <future>
#include <chrono>
#include <iostream>

int main() {

 std::future<double> fut = std::async([](double x)->double { return pow(x,2); }, 80);
 fut.wait();
 std::shared_future<double> shared = fut.share();
 std::cout << shared.get() << std::endl;
 return 0;

}

月曜日, 8月 18, 2014

STL - partial_sort

STLのalgorithmにはpartial_sort()が用意されており,部分的にソートを適用することが出来る.
第一引数は開始要素,第二引数はソートを適用する上限,第三引数は終端要素.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;


int main() {

 vector<int> v{ 25, 80, 12, 5, 50, 61, 24, 37, 45, 70 };
 partial_sort(v.begin(), v.begin() + 3, v.end());
 for_each(v.begin(), v.end(), [](int x)->void { cout << x << endl; });

 return 0;

}
結果
5
12
24
80
50
61
25
37
45
70

日曜日, 8月 17, 2014

auto_ptrからunique_ptrへ移行

auto_ptrは既にdeprecatedとされており,短所もご存じの通りかと思う.(こちらはその短所を簡潔に良くまとめている)
auto_ptrからunique_ptrへの移行は非常に簡単である.

以下の例はauto_ptrの代わりにunique_ptrを使用して簡単なツリーをインオーダ順で走査するコード.

tree.h

#ifndef __TREEPRJ_TREE_H__
#define __TREEPRJ_TREE_H__

#include <string>
#include <memory>
#include <iostream>


class Node {
public:
 Node(int idVal, std::string nameVal) :id(idVal), name(nameVal){}
 virtual ~Node() { std::cout << "ID[" << id << "] is being released" << std::endl; }
 int id;
 std::string name;
 std::unique_ptr<Node> l;
 std::unique_ptr<Node> r;
};


class Tree {
private:
 std::unique_ptr<Node> root;
 void _add(std::unique_ptr<Node>& n, int id, std::string name);
 void _traverseInorder(std::unique_ptr<Node>& n);
public:
 Tree(int id, const std::string n);
 virtual ~Tree() {}
 void add(int id, std::string name);
 void traverseInorder();

};

#endif


tree.cpp
#include "tree.h"
#include <iostream>

Tree::Tree(int id, const std::string name) {

 root.reset(new Node(id, name));

}

void Tree::add(int id, std::string name) {

 _add(root, id, name);

}

void Tree::_add(std::unique_ptr<Node>& n, int newId, std::string newName) {

 if ( !n ) return;

 if (n->id > newId) {
  if (n->l) {
   _add(n->l, newId, newName);
  }
  else {
   n->l.reset(new Node(newId, newName));
  }
 }
 else {
  if (n->r) {
   _add(n->r, newId, newName);
  }
  else {
   n->r.reset(new Node(newId, newName));
  }
 }

}

void Tree::traverseInorder() {

 _traverseInorder(root);

}

void Tree::_traverseInorder(std::unique_ptr<Node>& n) {

 if (!n) return;
 _traverseInorder(n->l);
 std::cout << "ID:" << n->id << ",NAME:" << n->name << std::endl;
 _traverseInorder(n->r);

}

int main() {

 Tree t(30, "The Colton");
 t.add(25, "The Warwick");
 t.add(21, "Hawthorne Court");
 t.add(45, "Hampton Court Garden");
 t.add(15, "The Belvedere");
 t.add(50, "Stratford Hall");
 t.traverseInorder();

}


日曜日, 7月 20, 2014

Spring プロファイル

プロファイルを変えることでインジェクトするデータ内容を変えたりしたいこともあるかもしれない.
Springでプロファイルを使用するのは簡単で,単にProfileアノテーションを使えばよい.
以下の例はプロファイルを有効に利用しているとは言えない例ではあるが..


package org.tanuneko;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App {

    public static void main( String args[]) {

        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.getEnvironment().setActiveProfiles( "profileA" );
        ctx.register( AppConfig.class );
        ctx.refresh();
        Data data = ctx.getBean( Data.class );
        System.out.println( data.getData() );

    }
}

package org.tanuneko;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;


@Configuration
@ComponentScan("org.tanuneko")
@Profile( {"profileA","profileB"} )
public class AppConfig {

    @Bean(initMethod="init",destroyMethod="destruct")
    public Data data() {
        return new Data();
    }
}


package org.tanuneko;

public class Data {

    private String data;

    public Data() {
        data = "test data.";
    }

    public void init() {
        System.out.println( "initialized" );
    }

    public void destruct() {
        System.out.println( "destroyed" );
    }

    public String getData() { return data; }
}


月曜日, 7月 14, 2014

モックのDI

IoCコンテナを使えば,テスト用にドライバ/スタブを容易にDIできる.
当然のことなのだが,意外にこの利点をあえて使わない(?)テストケースを書いてくることがままある.これを使えば当然テストコードはかなり可読性が高くなるので,使わない手はないはずだが.

以下はモックのDIの参考例.
以下の例では,DataDumpServiceのインタフェースを介してConsoleDataDumpService並びにDataNodeNodeIFインタフェースを介して テスト用データを持つDataNodeをユニットテスト中にDIする.

DataDumpServiceインタフェース

package org.tanuneko;

public interface DataDumpService {

    public void dump( Object obj );

}

ConsoleDumpServiceクラス

package org.tanuneko;

import org.springframework.stereotype.Service;

@Service
public class ConsoleDataDumpService implements DataDumpService {

    public void dump( Object obj ) {
        System.out.println( obj );
    }
}

NodeIFインタフェース

package org.tanuneko;

public interface NodeIF<X> {

    public X getData();
}

DataNodeクラス

package org.tanuneko;

public class DataNode<X> implements NodeIF {

    private X data;

    public DataNode( X data ) {
        this.data = data;
    }

    public X getData() {
        return data;
    }
}

AppConfig(非テスト用)

package org.tanuneko;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;


@Configuration
@ComponentScan("org.tanuneko")
public class AppConfig {

    @Bean
    public NodeIF data() {
        return new DataNode( "This is prod" );
    }
}

App(非テスト用)

package org.tanuneko;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;


public class App {

    public App() {

        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.register( AppConfig.class );
        ctx.refresh();
        NodeIF node = ctx.getBean( DataNode.class );
        System.out.println( node.getData() );
        DataDumpService srv = ctx.getBean( ConsoleDataDumpService.class );
        srv.dump( node.getData() );

    }

    public static void main( String args[] ) {

        App a = new App();

    }
}

テストアップランチャ

package org.tanuneko;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


@Component
public class TestAppLauncher {

    @Autowired
    DataDumpService dp;

    @Autowired
    NodeIF dataNode;

}

AppConfig(テスト用)

package org.tanuneko;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;


@Configuration
@ComponentScan("org.tanuneko")
public class AppTestConfig {

    @Bean
    public NodeIF data() {
        return new DataNode( "This is test" );
    }

}

テストクラス

package org.tanuneko;

import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


public class AppTest {

    private static TestAppLauncher testApp;

    @BeforeClass
    public static void init() {

        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.register( AppTestConfig.class );
        ctx.refresh();
        testApp = ctx.getBean( TestAppLauncher.class );

    }

    @Test
    public void testDataNode() {

        testApp.dp.dump( testApp.dataNode.getData() );

    }

}

金曜日, 7月 04, 2014

Java8 - Collectors 平均関連

業務用のコードでは使うことはあまりないが,あったら便利な,ストリームの要素から平均を抽出するコード.


        System.out.println(

            Stream.of(50d, 62d, 79.4d, 62d, 80.0d, 89.25d, 5d)
                .collect( Collectors.averagingDouble( (x)->x) ).doubleValue() + " " +
            Stream.of(20,15,30,45,50,25)
                .collect( Collectors.averagingInt( (x)->x ) ).intValue() + " " +
            Stream.of(300L, 200L, 100L, 400L, 500L )
                .collect( Collectors.averagingLong( (x)->x ) ).longValue()

        );


現実的な用途の一つとして考えられるのはメッセージキュー中のデータの平均サイズを取得するようなものだろう.以下は5つの別スレッド上で動作するデータプロバイダーがデータキューにデータを書き込んで、サンプラーが先頭から30個のデータの長さの平均を計算する例.

package org.tanuneko;

import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class DataSampler {

    private static final int MAX_SAMPLESIZE = 30;
    private CopyOnWriteArrayList<Data> q;

    public DataSampler() {
        q = new CopyOnWriteArrayList<>();
        Executors.newFixedThreadPool(5).execute( new DataProvider( this ) );
    }

    public void doSampling() {

        while( true ) {

            System.out.println(
            q.stream().limit( MAX_SAMPLESIZE ).mapToInt( Data::getDataSize )
                    .summaryStatistics().getAverage()
            );

            try {
                Thread.sleep( 2000 );
            } catch( InterruptedException iE ) {
                iE.printStackTrace();
                System.exit(1);
            }
            System.out.println( "(QSIZE=" + q.size() + ",MAXSAMPLESIZE=" + MAX_SAMPLESIZE + ")" );

        }

    }

    public void addData( Data d ) {
        q.add( d );
    }

    public static void main (String args[] ) {

        DataSampler d = new DataSampler();
        d.doSampling();

    }

}

class DataProvider implements Runnable {

    private DataSampler sampler;

    public DataProvider( DataSampler sampler ) {
        this.sampler = sampler;
    }

    public void run() {

        Random r = new Random();
        r.setSeed( System.currentTimeMillis() );

        while( true ) {

            sampler.addData( new Data( genRandBytes() ) );
            try {
                Thread.sleep( r.nextInt( 3000 ) );
            } catch (InterruptedException iE) {
                throw new RuntimeException(iE);
            }

        }
    }

    private byte[] genRandBytes() {

        Random r = new Random();
        r.setSeed( System.currentTimeMillis() );
        return Stream.generate(()->"a").limit( r.nextInt( 100 ) )
                .collect( Collectors.joining() )
                .getBytes();

    }
}

class Data {

    private byte[] buffer;
    public Data( byte[] buffer ) {
        this.buffer = new byte[ buffer.length ];
        System.arraycopy( this.buffer, 0, buffer, 0, buffer.length );
    }
    public byte[] getData() {
        return buffer;
    }
    public int getDataSize() {
        return buffer.length;
    }

}

火曜日, 6月 03, 2014

C++11 - std thread

C++11でstd::threadがサポートされた.pthreadがJavaでいうところのネイティブスレッドであれば,std::threadはさしずめExecutorServicesのような使いやすさである.

#include <mutex>
#include <chrono>
#include <random>
using namespace std;

mutex mutexObj;
random_device rd;
mt19937 mt(rd());

void dump(int val) {

 mutexObj.lock();
 this_thread::sleep_for(chrono::seconds(mt()%3));
 cout << "[" << this_thread::get_id() << "]:" << val*50 << endl;
 mutexObj.unlock();

}

int main() {

 vector<thread> threads;
 for (int i = 0; i < 5; i++)
  threads.push_back(thread(dump, i));

 for (auto& t : threads)
  t.join();

}

月曜日, 6月 02, 2014

C++11 - ムーブコンストラクタ

C++の特徴の一つ,ムーブコンストラクタ.rvalue参照により余計なデータのコピーを避けることができるため,大きなクラスや構造体のハンドリングに関しては高速化が期待できる.

以下の例はムーブコンストラクタを使ってトレードデータクラスをスワップする例.コピーコンストラクタと異なり,セールスパーソンのリスト及びブロブデータ(この例では簡略化の為stringで代用)の転送をしている.
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

typedef std::shared_ptr BLOB;

class TradeData {
private:
 int _tradeId;
 vector _salesPersonIds;
 string _note;
 BLOB _blob;

public:
 TradeData(int tradeId, initializer_list salesPersonIds, string note, string blobInfo) : _tradeId(tradeId), _salesPersonIds(salesPersonIds), _note(note){
  for (auto iter = salesPersonIds.begin(); iter != salesPersonIds.end(); iter++) {
   _salesPersonIds.push_back(*iter);
  }
  _blob = make_shared(blobInfo);
 }

 virtual ~TradeData() {
 }

 const char* operator()() {
  strstream buf;
  buf << _tradeId << ":[";
  for_each(_salesPersonIds.begin(), _salesPersonIds.end(), [&buf](int id){ buf << id << ","; });
  buf << "]," << _note << "," << *_blob << "(@" << _blob << ")" <<  ends;
  return buf.str();
 }

 TradeData& operator=(TradeData&& trade) {
  _blob = trade._blob;
  trade._blob = nullptr;
  _tradeId = trade._tradeId;
  _salesPersonIds = trade._salesPersonIds;
  _note = trade._note;
  return *this;

 }

};

void SwapTrade(TradeData& td1, TradeData& td2) {

 TradeData temp = std::move(td1);
 td1 = std::move(td2);
 td2 = std::move(temp);

}

int main() {

 TradeData t1(100, { 1, 2, 3 }, "test trade1", "blobdata1..");
 TradeData t2(300, { 1 }, "test trade2", "blobdata2..");
 cout << "! before swap" << endl;
 cout << "*** tradedata1 *** " << t1() << endl;
 cout << "*** tradedata2 *** " << t2() << endl;
 SwapTrade(t1, t2);
 cout << "! after swap" << endl;
 cout << "*** tradedata1 *** " << t1() << endl;
 cout << "*** tradedata2 *** " << t2() << endl;

}


日曜日, 6月 01, 2014

C++11 - 簡単なランダム順列

C++11の一部機能を用いて簡単なランダム(値の重複無し)の順列を生成するコード.

#include <iostream>
#include <vector>
#include <random>
#include <algorithm>
using namespace std;

void d(const vector<int> v) {
 for_each(v.begin(), v.end(), [](int x)->void{ cout << x << endl; });
}

int main() {

 random_device rd;
 mt19937 mt(rd());
 vector<int> vals{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
 for (auto i = 0; i < vals.size(); i++) {
  auto idx = mt() % vals.size();
  auto t = vals[idx];
  vals[idx] = vals[i];
  vals[i] = t;
 }

 d(vals);


}

水曜日, 5月 28, 2014

C++のラムダ

Java8でついにラムダ式が..というのは間違いなくビッグニュースではあるが,一方C++も既にラムダをC++0x以降で既にサポート済みであることを述べておかないのはある意味フェアではなかろう.

以下の例はinitializer_list経由でリストの 配列を取り,リストの値はラムダ式のpredを使いソート,そして指定された関数で出力する例.

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;


class Tako {
private:
 vector<signed> v;
public:
 Tako(initializer_list<signed> listVal);
 virtual ~Tako() {}
 void dump(void (f)(const signed));
 void sort();
};

Tako::Tako(initializer_list<signed> listVal) {

 for (auto a : listVal) {
  v.push_back(a);
 }
}

void Tako::dump(void (f)(const signed)) {
 for (auto x : v) {
  f(x);
 }
}

void Tako::sort() {

 if (v.size() >= 2) {
  std::sort(v.begin(), v.end(), [](signed x, signed y)-> signed { return x > y; });
 }

}

void dump_to_stdout(const signed v) {
 cout << v << endl;
}

int main() {

 Tako t = { 32, 27, 30, 50, 64, 10 };
 void(*myfunc)(signed) = dump_to_stdout;
 t.sort();
 t.dump(myfunc);


}

日曜日, 5月 18, 2014

Java8 - コレクター マップ

問題

String型のリストをstreamを使用してマップに変換せよ.そのリストの各要素は変換されたマップの値とする.キーは任意の整数値を割り当ててよい.

ヒント

Collectors.map()メソッドの基本知識をただ問うているだけの問題.

解答

       Stream.of("tako", "pako")
                .collect( toMap( x -> ++ctx, y -> y, (a,b) -> a + b ) )
                .forEach( (x,y) -> System.out.println( x + ":" + y ) );


火曜日, 5月 13, 2014

走り書き - 草を生やす

草を生やす,緑豊かなコードである.
package org.tanuneko;

import java.util.Arrays;

public class Kusa {

    public static void main( String args[] ) {

        System.out.println(
            Arrays.asList( "This is a pen".split( " " ) ).stream()
                    .map( x -> "ww" + x + "ww" )
                    .reduce( "(^o^)", String::concat )
                    .toString()
        );

    }

}


日曜日, 5月 04, 2014

2次元配列から重複を検索

問題
In a 2-D matrix, every row is increasingly sorted from left to right, and the last number in each row is not greater than the first number of the next row. A sample matrix follows. Please implement a function to check whether a number is in such a matrix or not. It returns true if it tries to find the number 7 in the sample matrix, but it returns false if it tries to find the number 12.
1   3   5
7   9   11
13  15  17
(Coding Interviews: Questions, Analysis & Solutionsより引用)

ヒント
2次元配列である必要などない.


基本的には2次元配列である必要がないため,一次元配列にするか,このまま2次元配列に2分検索をするか.ここでは前者の方法をとっている.


package org.tanuneko;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by morinoko on 5/3/2014.
 */
public class DupeFound {

    static int bsearch( List<Integer> l, int val ) {

        int s = 0;
        int e = l.size() - 1;
        int m = 0;
        while( s <= e ) {
            m = l.get((s + e) / 2);
            if (m == val)
                return (s + e) / 2;
            else if (m < val)
                s = ((s + e) / 2) + 1;
            else
                e = ((s + e) / 2) - 1;
        }
        return -1;
    }


    public static void main( String args[] ) {

     
    List<Integer> l = Arrays.asList( "1 3 5", "7 9 11", "13 15 17" )
            .stream()
            .flatMap(x -> Arrays.stream(x.split(" ")))
            .mapToInt(x -> Integer.parseInt(x))
            .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);

    int m = l.get( l.size() / 2 );

    System.out.println( bsearch( l, 5 ) );
    System.out.println( bsearch( l, 14 ) );
}
}

土曜日, 5月 03, 2014

マルチスレッド - notifyとwait

問題
There are three threads in a process. The first thread prints 1 1 1 …, the second one prints 2 2 2 …, and the third one prints 3 3 3 … endlessly. How do you schedule these three threads in order to print 1 2 3 1 2 3 …?
(Coding Interviews, Analysis & Solutions より引用)

ヒント
各スレッド間でchain of responsibility的に連係動作させるか,マスタスレッドがnotify/waitを利用してオーケストレーションするか等,解法は色々ある.

解答

ここではヒントの後者の方法を実装してみた.

package org.tanuneko;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * Created by morinoko on 5/3/2014.
 */
public class MyThread implements Runnable {

    private static final int NUM_TH = 3;
    private final int id;
    private final int val;
    private static Object[] objs = new Object[NUM_TH];

    static {
        for( int i = 0;i < objs.length;i++ ) {
            objs[i] = new Object();
        }
    }

    public MyThread( int id,int val ) {
        this.id = id;
        this.val = val;
    }

    public void run() {

        while( true ) {

            synchronized( objs[id] ) {

                try {
                    objs[id].wait();
                } catch ( InterruptedException iE ) {
                    iE.printStackTrace();
                }
            }
            System.out.println( val );

        }
    }

    public static void main( String args[] ) throws InterruptedException {

        ExecutorService s = Executors.newFixedThreadPool( NUM_TH );
        for( int i = 0;i < NUM_TH;i++ ) {
            s.execute( new MyThread( i, i + 1) );
        }

        int invokeTarget = 0;
        while( true ) {
            synchronized( objs[invokeTarget] ) {
                objs[invokeTarget].notify();
            }

            Thread.sleep( 1000 );
            invokeTarget = ++invokeTarget % NUM_TH;
        }

    }

}

Groovy - JsonSlurperとJsonBuilder

最近仕事でGroovyを選ぶことが多い.やはりスピードを最優先かつシェルスクリプトでは要求にこたえられない場合はGroovy又はPythonを選ぶことになる.

しかしGroovyは書けば書くほど,便利で病みつきになる言語である.Groovy JDKも便利なものばかりで,おそらく通常のJavaコードを書くより効率は倍,コード量も半分以下になっていると感じる.

とりわけ便利であると思ったものをいくつか紹介していきたい.

一つ目はJsonSlurperとJsonBuilder.JSonSlurperは,名前の通りJsonオブジェクトをずずっとパースしてGroovyオブジェクトにアンマーシャルしてくれる.JsonSlurperは多くのparseオーバロード メソッドを提供しているので,JsonSlurperの為に入力データを加工する手間も省けることも多いだろう.
一方JsonBuilderはGroovyオブジェクトからJSONデータへのマーシャリング機能を提供している.
以下の例はJSONメッセージをアンマーシャル後,再びマーシャルする例.


import groovy.json.JsonBuilder
import groovy.json.JsonSlurper

jsonMsg = "{\n" +
        "    \"title\": \"The Latin Bit\",\n" +
        "    \"Label\": \"BlueNote\",\n" +
        "    \"Janre\": \"Jazz\",\n" +
        "    \"Leader\": [\n" +
        "        \"Grant Green\"\n" +
        "    ],\n" +
        "    \"Release\": 1962,\n" +
        "    \"TrackRecords\": [\n" +
        "        {\n" +
        "            \"All Tracks\": [\n" +
        "                \"Grant Green(g)\",\n" +
        "                \"John Acea(p)\",\n" +
        "                \"Wendell Marshall(b)\",\n" +
        "                \"Willie Bobo(ds)\",\n" +
        "                \"Carlos 'Patato' Valdes(conga)\",\n" +
        "                \"Garvin Masseaux(chekere)\"\n" +
        "            ]\n" +
        "        }\n" +
        "    ]}"

def parseJson( jsonData ) {

    JsonSlurper json = new JsonSlurper()
    return json.parseText( jsonData )

}

def buildJson( obj ) {

    def builder = new JsonBuilder( obj )
    return builder.toPrettyString()
}

// main

def parsed = parseJson( jsonMsg )
println( parsed )
assert parsed.title == "The Latin Bit"
assert parsed.Release == 1962
assert parsed.Leader[0] == "Grant Green"
assert parsed.TrackRecords["All Tracks"][0].indexOf( "John Acea(p)" ) != -1

println( buildJson( parsed ) )





月曜日, 4月 28, 2014

フィボナッチ数を求めるコード

フィボナッチ数の漸化式を考えてみれば - f(n+2) = f(n) + f(n+1) -, いうまでもなく再帰を書きたくなるだろうし,実際にそういう解答をする人も多いし,そんなコードのサンプルをあげているサイトも多いし..という.まぁ曲者である.Java,C++等をはじめとするコードでそんなコードを書いて,大きな値の引数を渡せばあっというまにスタックオーバーフローで動かない.現代のコンパイラやインタプリタならきっと末尾再帰で最適化してくれる,なんていうことを期待してコードを書くのはやめたほうがよいと思う.

フィボナッチ数のように,複数の再帰呼び出しを必要とするロジックなら素直にループで書こう.

    private static void fib( int max ) {

        int total = 0;
        int prev1 = 0;
        int prev2 = 1;

        for( int i = 0;i < max;i++ ) {
            if( i == 0 ) prev1 = 0;
            else if( i == 1 ) prev2 = 1;
            else {
                prev2 = prev1;
                prev1 = total;
            }
            total = prev1 + prev2;
        }

        System.out.println( total );

    }

Java - インターセクションの検出

インターセクションを検出するコードで,以下のサイトの解答例にはなかなか感心したので紹介.
シンプルでよいコードである.成程,HashSetのcontains()ならO(1)だ.

http://codereview.stackexchange.com/questions/9909/intersection-of-arrays-java

テストしたと書いていながら若干間違いがあるので,以下のように書き直し.

package org.tanuneko;

import java.util.*;

public class Intersect {

    private static List<Integer> intersect( final List<Integer> a, final List<Integer> b ) {

        Set<Integer> canAdd = new HashSet<Integer>(a);
        List<Integer> result = new ArrayList<>();
        for( int n : b ) {
            if( canAdd.contains(n) ) {
                result.add(n);
                canAdd.remove(n);
            }
        }
        return result;
    }

    public static void main( String args[] ) {

        List<Integer> a = Arrays.asList( 4,2,6,1,8,9,5 );
        List<Integer> b = Arrays.asList( 8,6,3,5,0,10,1 );

        System.out.println( intersect( a,b ) );
    }

}


土曜日, 4月 26, 2014

メシウマという言葉

メシウマというネットスラングがあり,その意味は他人の不幸を肴に飯がうまい,という意味であるが,何とも心が貧しい感じで関心しない.

好きな球団が勝利して,そのあとの飯がうまい,というのが良いと思うが.

日曜日, 4月 20, 2014

自己結合

自己結合は必ず使いこなせたほうが良い,というのはいうまでもないことだが,意外とわかってない人もどうやら多いようだ.

自己結合は,言ってみればなんのこともない,単にある外部キーが同テーブル上にあるプライマリキーと結合するだけである.良い好例と説明がこちらにあるので,理解があいまいだと思われる方は是非とも一読されたい.以下はSQLite3.5.9上で動作する解答例.

drop table if exists Employee
go
create table Employee (
 Id int not null primary key,
 Name varchar(64) not null,
 ManagerId int,
 Salary int not null 
)
go
insert into Employee (Id,Name,ManagerId,Salary) values( 1, "Kotora", 3, 500000 )
go
insert into Employee (Id,Name,ManagerId,Salary) values( 2, "Kodanuki",3,  5000 )
go
insert into Employee (Id,Name,Salary) values( 3, "Tanu", 100000 )
go
insert into Employee (Id,Name,Salary) values( 4, "Ushi", 5000 )

select e2.Name,"earns more than" as fact,e1.Name from Employee e1
join Employee e2 on e1.Id = e2.ManagerId
where e2.Salary > e1.Salary

土曜日, 4月 19, 2014

BTreeの判定

何かよいインタビュー用の問題はないかリサーチしていたところ,ツリー構造のデータが二分木であるかどうか判定するコードを書け,というのが結構あることがわかった.

確かに基礎を見るにはよい問いかもしれない.
深さ優先ではこんな感じだろうか.

#include <iostream>
#include <string>
using namespace std;

typedef struct Node_Struct {
 int value;
 struct Node_Struct* l;
 struct Node_Struct* r;
} Node;

Node * add(Node* base, int value) {

 if (base == NULL) {
  cout << "adding " << value << " to this node" << endl;
  base = new Node;
  base->l = base->r = NULL;
  base->value = value;
 }
 else if (base->value > value) {
  cout << base->value << ">" << value << ".. L" << endl;
  base->l = add(base->l,value);
 }
 else {
  cout << base->value << "<" << value << ".. R" << endl;
  base->r = add( base->r, value);
 }
 return base;

}

void dump(const Node* n) {
 cout << "{" << "value:" << n->value << "}" << endl;
}

void traverse_r( Node* n ) {

 if (n == NULL)
  return;

 if (n->l != NULL)
  traverse_r(n->l);
 dump(n);
 if (n->r != NULL)
  traverse_r(n->r);

 
}


Node* build_btree( Node* n) {

 n = add(n, 15);
 n = add(n, 30);
 n = add(n, 48);
 n = add(n, 10);
 n = add(n, 15);
 n = add(n, 72);
 n = add(n, 60);
 n = add(n, 66);
 n = add(n, 26);
 n = add(n, 55);
 return n;

}

bool is_btree_d(Node *n, bool decision) {
 
 if (n == NULL || decision == false)
  return decision;
 if (n->l != NULL && n->r != NULL) {
  cout << n->l->value << ":" << n->r->value << endl;
  decision = n->l->value < n->r->value ? true : false;
 }

 cout << "movin to l" << endl;
 decision = is_btree_d(n->l, decision);
 cout << "moving to r" << endl;
 decision = is_btree_d(n->r, decision);
 return decision;
 
}

int main() {

 Node* n = NULL;
 n = build_btree(n);
 traverse_r( n );
 cout << "is this btree valid? - " << is_btree_d(n, true) << endl;

 return 0;
}


月曜日, 4月 14, 2014

Java - Mapのイテレーション

Mapのイテレーションをするコードをレビューすることもあるし,もはやそのやり方も人口に膾炙していると思う.しかし,keySet()を最初に取得し,keySetのイテレータを通して要素にアクセスするコードを見るのもまた事実でもある.コードの静的解析ツールを走らせばすぐに指摘してくれるはずなので,レビュー前にはぜひ修正をしてもらいたいものである.


import java.util.HashMap;
import java.util.Map;

public class MapIter {

    public static void main( String args[] ) {

        Map<String,String> data = new HashMap<String,String>();
        data.put( "F", "Fine Fare" );
        data.put( "B", "Biking" );
        data.put( "C", "C Town Town Town" );

        for( Map.Entry<String,String> ent : data.entrySet() ) {
            System.out.printf("%s:%s\n",ent.getKey(),ent.getValue());
        }

    }
}

火曜日, 4月 08, 2014

デッドロック

時々私が使う面接の質問のひとつはデッドロックを起こすコードを書いてみてください,というものである.多くの候補者は理論的にはわかってはいるものの,コードでいざ書く段になるとなぜか正しい答えを書けないのである.

以下にサンプルのコードを示す.以下のコードや,Oracle Javaのデッドロックの参考例,哲学者の食事問題などを参考にしてほしい.

class Friend extends Thread implements Runnable {

    private Friend myFriend;
    private String name;

    public Friend( final String name ) {
        this.name = name;
    }

    public synchronized void vow() {
        System.out.printf( "Hey my friend %s..\n", name );
        myFriend.vow();
    }

    public void run() {
        vow();
    }

    public void setMyFriend( Friend myFriend ) {
        this.myFriend = myFriend;
    }

    public static void main( String args[] ) {
        Friend me = new Friend( "John Flansburgh" );
        Friend dude = new Friend( "John Linnell" );
        me.setMyFriend( dude );
        dude.setMyFriend( me );
        me.start();
        dude.start();
        System.out.println( "Have a nice day." );
    }
}





土曜日, 4月 05, 2014

走り書き2

バブルソートの走り書きのついでに選択ソートも。。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

void dump(int dump) {
 cout << dump << ",";
}

void selsort(vector<int>& v) {

 cout << "before:";
 for_each(v.begin(), v.end(), dump);
 cout << endl;

 int min;
 int t;
 for (int i = 0; i < v.size() - 1; i++) {
  min = i;
  for (int j = i + 1; j < v.size(); j++) {
   if (v[j] < v[min]) {
    min = j;
   }
  }
  t = v[i];
  v[i] = v[min];
  v[min] = t;
 }

 cout << "after:";
 for_each(v.begin(), v.end(), dump);
 cout << endl;

}


int main() {

 int nums[] = { 32, 22, 25, 10, 9, 38, 40, 42, 50, 51, 10, 32, 45, 27 };
 vector<int> v;
 for (int i = 0; i < sizeof(nums) / sizeof(int); i++)
  v.push_back(nums[i]);

 selsort(v);

}

金曜日, 4月 04, 2014

走り書き

妙にバブルソート(!)が書きたくなったので,走り書きをした.
サイダーが飲みたくなった.


import java.util.List;


public class Bubb {

    static void bubble( int[] nums ) {

        int t;
        for( int i = 0;i < nums.length - 1;i++ ) {
            for( int j = i + 1; j < nums.length; j++ ) {
                if( nums[i] > nums[j] ) {
                    t = nums[i];
                    nums[i] = nums[j];
                    nums[j] = t;
                }
            }
        }
    }

    public static void main( String args[] ) {

        int[] nums = { 32, 17, 21, 26, 35, 40, 10, 5, 8, 9, 48, 23, 16, 17 };
        bubble( nums );
        for( int i = 0;i < nums.length;i++ ) {
            System.out.println( nums[ i ] );
        }

    }
}


日曜日, 3月 30, 2014

問題 - 三角形の上段から下段へのトラバース

問題

By starting at the top of the triangle, move to adjacent numbers on the row below. On moving down to the below node, choose higher number. Produce the sum of the route.

e.g.
        6
     7     8
  6     5    12
9   8     10     6

The route should be 6 -> 8 -> 12 -> 10. So the sum of the route is 40.

簡単な問題なので,たウォーミングアップ程度には丁度よいかと思われる.

ヒント

三角形を一次元のリストにマップして,インデックスをスライドさせていく.
三角形の格段の要素数は x(n)=n.


解答

import org.apache.commons.io.FileUtils;

import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

public class TrianglePuzzle {

    private static final String SEPARATOR = " ";
    private final File puzzleFile;

    public TrianglePuzzle( final String fileName ) throws IOException {
        this.puzzleFile = new File( TrianglePuzzle.class.getClassLoader().getResource( fileName ).getFile() );
        if( !puzzleFile.exists() || !puzzleFile.isFile() || puzzleFile.length() == 0 )
            throw new IOException( "File must be file with proper content" );
    }

    public long calc() throws IOException {

        Stack<Long> trace = new Stack<Long>();
        List<Long> vals = parse();
        int step = 0;
        int sel = 0;
        int stepTotal = 0;
        int val = 0;

        long lval = 0;
        long rval = 0;

        // step 1 is automatically first item
        trace.push( vals.get( 0 ) );
        stepTotal += ++step;

        // step 2 - N .. only adjacent numbers are checked
        while( stepTotal != vals.size() ) {
            lval = vals.get( stepTotal + sel );
            rval = vals.get( stepTotal + sel + 1 );
            System.out.println( lval + "," + rval );
            sel = lval > rval ? sel : sel + 1;
            System.out.println( vals.get( stepTotal + sel ) + " picked." );
            trace.push( vals.get( stepTotal + sel ) );
            System.out.println( "stepTotal=" + ( stepTotal ) );

            stepTotal += ++step;
        }

        // With Java8 code should be like return trace.stream().sum()
        Iterator<Long> iter = trace.iterator();

        int total = 0;
        while( iter.hasNext() ) {
            total += iter.next();
        }
        return total;

    }

    final List<Long> parse() throws IOException {

        List<Long> vals = new ArrayList<Long>();
        BufferedReader br = new BufferedReader( new InputStreamReader( new FileInputStream( puzzleFile ) ) );
        String line = null;
        while( ( line = br.readLine() ) != null ) {
            StringTokenizer st = new StringTokenizer( line, SEPARATOR );
            while( st.hasMoreTokens() ) {
                vals.add( Long.parseLong(st.nextToken()) );
            }
        }
        return vals;

    }

    public static void main( String args[] ) throws IOException {
        if( args.length != 1 ) {
            System.out.println( "arg length must be 1" );
            System.exit( 0 );
        }
        TrianglePuzzle tp = new TrianglePuzzle( args[ 0 ] );
    }
}



水曜日, 3月 05, 2014

Java8 - Void 関数の参照

void関数への参照にはProducerを使う.

        Consumer<String> dumper = (x)->System.out.println(x);
        List<String> stars = Arrays.asList("mai","mao","yuzuru");
        stars.stream().forEach(dumper);

Java8 - mapToObj()でキャラクタストリームの作成

文字列からキャラクタストリームを作るにはどうしたらよいか?
色々とやり方はあるだろうがワンライナーでやりたいとしたらおそらくこうなるのでは.

"abcde".chars().mapToObj(x->(char)x).forEach(System.out::println);

日曜日, 2月 23, 2014

今更デザインパターン - Strategy

Strategyパターンは,既存システムの機能拡張,とりわけ別のプロトコルへの適応といった場合や,汎用的なケースに対応できるシステムの開発において使われると思われる.

例えば最初はデータをすべてNFSディスクに保存する仕様だったのが,次に,代わりにデータをHDFSに保存するように仕様変更する,といった具合である.

このような場合に解放/閉鎖原則に遵守しつつシステム変更を行う定石の一つとしてStrategyパターンを適用することであろう.

Strategyパターンはアルゴリズム・ロジックをカプセル化し,呼び出しクラスからはそれらが可換であることを満たす必要がある.

以下の例は日本語変換ロジックとドイツ語変換ロジックをカプセル化し,呼び出し元において変換ロジックをドイツ語から日本語に取り換えている.

#include <iostream>
#include <string>
#include <stdexcept>
using namespace std;

class TransAlg {
public:
 virtual string translate(const string str) = 0;
};

class GermanTrans:public TransAlg {
public:
 virtual string translate(const string str) {
  if( str == "welcome" )
   return "willkommen";
  else
   return "weiss nicht";
 }
};

class JapanTrans:public TransAlg {
public:
 virtual string translate(const string str) {
  if( str == "welcome" )
   return "yokoso";
  else
   return "wakannai";
 }
};

class Translator {

private:
 TransAlg* m_alg;
 bool isReady;
public:
 Translator():isReady(false) {}
 string translate(const string str);
 void SetAlg(TransAlg* alg) { m_alg = alg; isReady = true; }
};

string Translator::translate(const string str ) {

 if( isReady ) {
  return m_alg->translate(str);
 }
 else
  throw logic_error("algorithm not set") ;
}


int main() {

 TransAlg* alg;
 alg = new GermanTrans();
 Translator trans;

 try {
  trans.SetAlg(alg);
  cout << "translating to German:" << trans.translate("welcome") << endl;
  delete alg;
  alg = new JapanTrans();
  trans.SetAlg(alg);
  cout << "translating to Japanese:" << trans.translate("welcome") << endl;
  delete alg;
 }catch(exception& e) {
  cerr << "err:" << e.what() << endl;
 }

}

今更デザインパターン - Visitor

知ってて当然というレベルまで普及した(少なくともGoFの)デザインパターンであるが,中には使用頻度が低いものもある.

使用頻度が低いといってもそれらを知っていて,適切に利用できるかどうかは大きな違いを生むのではないだろうか.

ということでそのようなややFactoryやsingletonに比べてマイナーなデザインパターンをいくつか取り上げる.

Visitor

アルゴリズム及びロジック部分をオブジェクトから切り離す,正に関心の分離を体現するデザインパターンの一つがVisitorである.

あるオブジェクトがロジックを持つのではなく,代わりにvisitorオブジェクトにロジックを持たせる.
そしてそのvisitorオブジェクトを他オブジェクトに訪問(visit)を受け入れ(accept)させて,ロジックをそのオブジェクト内で実行させる.

以下の例はNodeの子クラスにDumpVisitor具象クラスの訪問を受け入れる例である.



#include <iostream>
#include <string>
using namespace std;

class VisitorIF;

class Node {
public:
 virtual void accept(VisitorIF* v) = 0;
};

class FileNode:public Node {
private:
 int m_id;
public:
 FileNode(int id):m_id(id){}
 int GetID() { return m_id; }
 virtual void accept(VisitorIF* v);
};

class DirectoryNode:public Node {
private:
 int m_id;
public:
 DirectoryNode(int id):m_id(id){}
 int GetID() { return m_id; }
 virtual void accept(VisitorIF* v);
};

class VisitorIF {
public:
 virtual void visit(FileNode* n) = 0;
 virtual void visit(DirectoryNode* n) = 0;
};

class DumpVisitor:public VisitorIF {

 virtual void visit(FileNode* n){ cout << "<<FILE>>" << n->GetID() << endl; }
 virtual void visit(DirectoryNode* n){  cout << "<<DIR>>" << n->GetID() << endl; }

};

void FileNode::accept(VisitorIF* v) {

 v->visit(this);

}

void DirectoryNode::accept(VisitorIF* v) {

 v->visit(this);

}

int main() {

 VisitorIF* v = new DumpVisitor();
 FileNode fn(10);
 DirectoryNode dn(20000);
 fn.accept(v);
 dn.accept(v);
 delete v;
}


火曜日, 1月 21, 2014

Java8 - 関数の合成 1 .. andThen

Java8のラムダは関数の合成に対する操作も用意されている.
そのうちの一つがandThen()である.以下の例は引換券のIDを入力として本のタイトルを返す.


package org.tanuneko;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.stream.Collectors.*;

public class AndThenSample {

    private static List<ClaimTicket> tickets;

    private static void init() {

        tickets = new ArrayList<ClaimTicket>();
        tickets.add( new ClaimTicket( 1, new Book( Janre.Sports, "All about Payton Manning") ) );
        tickets.add( new ClaimTicket( 2, new Book( Janre.Sports, "Andy - how to win at playoff") ) );
        tickets.add( new ClaimTicket( 3, new Book( Janre.Education, "ABC") ) );
        tickets.add( new ClaimTicket( 101, new Book( Janre.Education, "Waldorf education - how it works") ) );

    }

    public static void main( String args[] ) {

        init();
        Function<ClaimTicket,Book> getBookByClaimId = ClaimTicket::getBook;
        Function<Book,String> getTitle = Book::getTitle;
        Function<ClaimTicket,String> getTitleOfClaimedBook = getBookByClaimId.andThen(getTitle);
        System.out.println( tickets.stream().filter(x->x.getId()<100)
                .map(getTitleOfClaimedBook)
                .collect( Collectors.reducing((x,y)-> x + "," + y))
                .toString() );
    }

}

enum Janre {
    Education,
    Sports
}

class Book {

    private Janre janre;
    private String title;

    public Book( Janre janre, String title ) {
        this.janre = janre;
        this.title = title;
    }

    public Janre getJanre() { return janre; }
    public String getTitle() { return title; }
}

class ClaimTicket {

    private int id;
    private Book book;

    public ClaimTicket( final int id, final Book book ) {
        this.id = id;
        this.book = book;
    }

    public int getId() { return id; }
    public Book getBook() { return book; }
}

Java8 - Infiniteのstream

Stream.iterate()を使うとinfiniteのstreamを生成できる.infiniteのstream - ここではiterateの2番目の引数UnaryOperator<T> ( 引数Tを取り,処理後結果として入力と同型Tを返す.つまりFunction<T,T> )を無制限に適用しstreamの要素を生成する.

おおよその場合はStream.limit()と組み合わせて使う.
package org.tanuneko;

import java.util.stream.Stream;

public class ToMapSample {

    public static void main( String args[] ) {

        Stream.iterate( 'S', (x)->"ABC".charAt((int)(Math.random()*3)))
                .limit(30)
                .forEach(System.out::println);

    }

}

土曜日, 1月 18, 2014

Java8 - キーごとに分類

以下の例は本オブジェクトのリストに対し,各本のジャンルごとに分類した結果をマップにして返す例.IntelliJのエディタではシンタックスエラーが出るが,コンパイルも実行も問題ない.


package org.tanuneko;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import static java.util.stream.Collectors.*;

public class ToMapSample {

    private static List<Book> books;

    private static void init() {

        books = new ArrayList<Book>();
        books.add( new Book( Janre.Sports, "All about Payton Manning") );
        books.add( new Book( Janre.Sports, "Andy - how to win at playoff")  );
        books.add( new Book( Janre.Education, "ABC") );
        books.add( new Book( Janre.Education, "Waldorf education - how it works")  );

    }

    public static void main( String args[] ) {

        init();
        Map<Janre,List<String>> map = books.stream()
                .collect(groupingBy(Book::getJanre,TreeMap::new,mapping(Book::getTitle,toList())));
        System.out.println(map);

    }

}

enum Janre {
    Education,
    Sports
}

class Book {

    private Janre janre;
    private String title;

    public Book( Janre janre, String title ) {
        this.janre = janre;
        this.title = title;
    }

    public Janre getJanre() { return janre; }
    public String getTitle() { return title; }
}




水曜日, 1月 15, 2014

Java8 - streamとDirectoryWalkerで効率よくファイル探索

Java IO CommonsのDirectoryWalkerとstreamを組み合わせて,効率よくファイルシステム上のデータを探すコード.かなり荒削りのサンプルだが,とりあえず動く.

package org.tanuneko.tanukin;

import org.apache.commons.io.DirectoryWalker;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.filefilter.IOFileFilter;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.stream.Collectors;

public class DirWalker extends DirectoryWalker<File> {

    private static FileFilter filter = getFilter();

    public DirWalker() {

        super( filter,-1 );

    }

    protected void handleFile( File file, int depth, Collection<File> results ) {

        results.add( file );

    }

    public Collection<File> start( File startDir ) throws IOException {
        Collection<File> results = new ConcurrentLinkedQueue<File>();
        super.walk( startDir, results );
        return results;
    }

    public static void main(String args[] ) throws IOException {

        DirWalker walker = new DirWalker();
        System.out.println(
                        walker.start(new File("C:\\cygwin\\srv")).parallelStream()
                        .map(x -> x.getAbsolutePath())
                        .collect(Collectors.toStringJoiner("\n"))
                        .toString());

    }

    // if you want to handle directory, define below
    /*
    protected boolean handleDirectory( File dir, int depth, Collection<File> results ) {

        if( ".svn".equals( dir.getName() ) ) {
            return false;
        }
        else {
            return true;
        }
    }
    */

    private static FileFilter getFilter() {

        //    you can define filter
        //    IOFileFilter suffixFilt =  FileFilterUtils.suffixFileFilter( ".txt" );
        //    FileFilterUtils.makeSVNAware( suffixFilt );
        //   FileFilter filter = FileFilterUtils.or( suffixFilt );
        //    return filter;
        return null;

    }

}

日曜日, 1月 12, 2014

Java8 - オブジェクトへのmapper適用

以下の例はJava8のmapを用いて,

  1. カスタムオブジェクトItemのマスタリスト中から興味のある品だけを取り出し
  2. 更に10000円以上のものだけを選び
  3. かつ価格を安いものから昇順に並べる

例である.


package org.tanuneko;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Reducer {

    public static void main( String args[] ) {

        // since this is lazy evaluation, WareHouse::findItembyId is not called for all entries in item list held by WareHouse
        List<Integer> interests = Arrays.asList( 1,2,3,4,5,6 );
        List<Item> items = interests.stream().map(WareHouse::findItembyId)
                            .filter((x)->x.getPrice()>10000)
                            .sorted( (x,y)->x.getPrice() - y.getPrice() )
                            .collect(Collectors.toList());
        items.stream().forEach(System.out::println);
 
     }

}

class WareHouse {

    static final List<Item> items = genItems();

    public static Item findItembyId( int id )  {
        // better to use orElse()
        return items.stream().filter(x->x.getId()==id).findFirst().get();

    }

    private static List<Item> genItems() {
        List<Item> items = new ArrayList<>();
        items.add( new Item( 1, 500, "Basket" ) );
        items.add( new Item( 2,1200, "Rack" ) );
        items.add( new Item( 3, 700, "Small Table" ) );
        items.add( new Item( 4, 50000, "Granite Table" ) );
        items.add( new Item( 5, 15000, "Closet" ) );
        items.add( new Item( 6, 400, "Grout" ) );
        items.add( new Item( 7, 28000, "Small Couch" ) );
        return items;
    }
}

Items.java

package org.tanuneko;

public class Item {

    private int id;
    private int price;
    private String name;

    public Item( int id, int price, String name ) {
        this.id = id;
        this.price = price;
        this.name = name;
    }

    public int getId() { return id; }
    public int getPrice() { return price; }
    public String getName() { return name; }

    @Override
    public String toString() {
        return "Item{" +
                "id=" + id +
                ", price=" + price +
                ", name='" + name + '\'' +
                '}';
    }
}

Item{id=5, price=15000, name='Closet'}
Item{id=4, price=50000, name='Granite Table'}

土曜日, 1月 11, 2014

Java8 - reduceとmapで集計

ついでにmapでカスタムオブジェクト群のあるフィールド値の合計をmapとreduceで行う例.

package org.tanuneko;

import java.util.ArrayList;
import java.util.List;
import java.util.function.BinaryOperator;

public class Reducer {

    public static void main( String args[] ) {

        System.out.println( genItems().stream().map( Item::getPrice ).reduce( Integer::sum ).get() );
        
     }

    private static List<Item> genItems() {
        List<Item> items = new ArrayList<>();
        items.add( new Item( 500, "Basket" ) );
        items.add( new Item( 1200, "Rack" ) );
        items.add( new Item( 700, "Small Table" ) );
        items.add( new Item( 50000, "Granite Table" ) );
        items.add( new Item( 15000, "Closet" ) );
        items.add( new Item( 400, "Grout" ) );
        return items;
    }

    private static Item getCheapestOne() {
        return new Item( Integer.MIN_VALUE, "VOID" );
    }
}

package org.tanuneko;

public class Item {
    private int price;
    private String name;

    public Item( int price, String name ) {
        this.price = price;
        this.name = name;
    }

    public int getPrice() { return price; }
    public String getName() { return name; }

    @Override
    public String toString() {
        return "Item{" +
                "price=" + price +
                ", name='" + name + '\'' +
                '}';
    }
}


Java8 - reduceで検索

Java8のstreamのreduceを使ってカスタムオブジェクト(この例ではItem)の検索をする例.


Item.java
package org.tanuneko;

import java.util.ArrayList;
import java.util.List;
import java.util.function.BinaryOperator;

public class Reducer {

    public static void main( String args[] ) {

        BinaryOperator<Item> costsMore = (m,n)->
                                          { return ( m.getPrice() > n.getPrice() ? m:n ); };

        System.out.println(genItems().stream().reduce(getCheapestOne(), costsMore));
     }

    private static List<Item> genItems() {
        List<Item> items = new ArrayList<>();
        items.add( new Item( 500, "Basket" ) );
        items.add( new Item( 1200, "Rack" ) );
        items.add( new Item( 700, "Small Table" ) );
        items.add( new Item( 50000, "Granite Table" ) );
        items.add( new Item( 15000, "Closet" ) );
        items.add( new Item( 400, "Grout" ) );
        return items;
    }

    private static Item getCheapestOne() {
        return new Item( Integer.MIN_VALUE, "VOID" );
    }
}

Item.java

package org.tanuneko;

public class Item {
    private int price;
    private String name;

    public Item( int price, String name ) {
        this.price = price;
        this.name = name;
    }

    public int getPrice() { return price; }
    public String getName() { return name; }

    @Override
    public String toString() {
        return "Item{" +
                "price=" + price +
                ", name='" + name + '\'' +
                '}';
    }
}
実行結果
Item{price=50000, name='Granite Table'}