日曜日, 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'}

火曜日, 12月 31, 2013

Java8 - stream

Java8の変更点の目玉の一つがstreamである.今までのfor文よりもずっときれいにデータプロセス用のコードが書けるようになる.

以下の例は,とある場外取引システムにおけるトレードデータから以下の条件を満たすものを抽出した例.

  • TradeDateが2013年1月1日以降
  • アクション名がADD
  • 取引相手先国が日本

package org.tanuneko.sample;

import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;

public class StreamSample {

    private static List<Trade> trades = populateTrades();
    private static List<CounterParty> cps = populateCPs();

    private static List<Trade> populateTrades() {
        List<Trade> list = new ArrayList<Trade>();
        list.add( new Trade( "TRD111.1", 1, "ADD", parse( "2013-01-20" ), 1001, true, "15000000ABC" ) );
        list.add( new Trade( "TRD123.1", 1, "ADD", parse( "2013-01-20" ), 1006, true, "16000000ABC" ) );
        list.add( new Trade( "TRD123.1", 2, "MOD", parse( "2013-01-26" ), 1006, true, "16000000ABC" ) );
        list.add( new Trade( "TRD145.1", 1, "ADD", parse( "2013-09-20" ), 1009, true, "T7000000ABC" ) );
        list.add( new Trade( "TRD133.1", 1, "ADD", parse( "2013-06-20" ), 1001, true, "16600000ABC" ) );
        list.add( new Trade( "TRD080.1", 1, "ADD", parse( "2010-07-20" ), 1001, true, "TRD080.1" ) );
        list.add( new Trade( "TRD092.1", 1, "ADD", parse( "2010-09-15" ), 1008, true, "TRD092.1" ) );
        list.add( new Trade( "TRD092.1", 2, "MOD", parse( "2010-09-30" ), 1020, true, "TRD092.1" ) );
        return list;
    }

    private static List<CounterParty> populateCPs() {
        List<CounterParty> cps = new ArrayList<CounterParty>();
        cps.add( new CounterParty( 1001, "US" ) );
        cps.add( new CounterParty( 1009, "Ireland" ) );
        cps.add( new CounterParty( 1006, "Japan" ) );
        cps.add( new CounterParty( 1020, "India" ) );
        cps.add( new CounterParty( 1008, "France" ) );
        cps.sort((l,r) -> l.getCounterPartyId() - r.getCounterPartyId()  );
        return cps;
    }

    private static ZonedDateTime parse( String date ) {
        return ZonedDateTime.parse( date + "T00:00:00-05:00[America/New_York]" );
    }

    public static void main( String args[] ) {
        
        trades.stream()
                .filter(t -> t.getTradeDate().isAfter(parse("2013-01-01")))
                .filter(t -> t.getActionName().equals("ADD") )
                .filter(t -> cps.stream().anyMatch( x -> x.getCounterPartyId() == t.getCounterPartyId() && x.getCountry().equals( "Japan" ) ) )
                .forEach(t -> System.out.println(t));
        cps.forEach( c -> System.out.println( c ) );
    }
}

class CounterParty {

    private int counterPartyId;
    private String country;

    CounterParty(int counterPartyId, String country) {
        this.counterPartyId = counterPartyId;
        this.country = country;
    }

    public int getCounterPartyId() {
        return counterPartyId;
    }

    public String getCountry() {
        return country;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        CounterParty that = (CounterParty) o;

        if (counterPartyId != that.counterPartyId) return false;

        return true;
    }

    @Override
    public int hashCode() {
        return counterPartyId;
    }

    @Override
    public String toString() {
        return "CounterParty{" +
                "counterPartyId=" + counterPartyId +
                ", country='" + country + '\'' +
                '}';
    }
}

class Trade {

    private String tradeId;
    private int eventId;
    private String actionName;
    private ZonedDateTime tradeDate;
    private int counterPartyId;
    private boolean isSDREligible;
    private String USI;

    public Trade( String tradeId, int eventId, String actionName, ZonedDateTime tradeDate,
                   int counterPartyId, boolean isSDREligible, String USI ) {
        this.tradeId = tradeId;
        this.eventId = eventId;
        this.actionName = actionName;
        this.tradeDate = tradeDate;
        this.counterPartyId = counterPartyId;
        this.isSDREligible = isSDREligible;
        this.USI = USI;
    }

    public String getTradeId() {
        return tradeId;
    }

    public int getEventId() {
        return eventId;
    }

    public String getActionName() {
        return actionName;
    }

    public ZonedDateTime getTradeDate() {
        return tradeDate;
    }

    public int getCounterPartyId() {
        return counterPartyId;
    }

    public boolean isSDREligible() {
        return isSDREligible;
    }

    public String getUSI() {
        return USI;
    }

    @Override
    public String toString() {
        return "Trade{" +
                "tradeId='" + tradeId + '\'' +
                ", eventId=" + eventId +
                ", actionName='" + actionName + '\'' +
                ", tradeDate=" + tradeDate +
                ", counterPartyId=" + counterPartyId +
                ", isSDREligible=" + isSDREligible +
                ", USI='" + USI + '\'' +
                '}';
    }
}



月曜日, 12月 30, 2013

Java8 新しい Date and Time API

Java8の新機能の一つが新しいDate and Time API(JSR-310)の追加だろう.ご存じの通り標準SDKに付属していた従来のDate関連のクラスは機能が貧弱であったり,Calendarクラスmutabilityに起因する懸念から,Joda Timeを使っていた.
この新しいDate and Time API(JSR-310)を使うか,Joda Timeを使い続けるかはあなた次第だが,少なくとも旧来のDateの実装で無理をし続ける必要だけはなさそうである.

ちなみに以下のサイトは良質なDate and Time APIのサマリ,Joda TimeとJSR-310の比較記事だと思う.

http://sssslide.com/www.slideshare.net/JustinSDK/2013-java-developer-day-joda-timejsr310
http://howtodoinjava.com/2013/05/15/date-and-time-api-changes-in-java-8-lambda/

LocalDate, ZoneDateTimeそしてDateTimeFormatterの使用例

import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;

/**
 * Created by morinoko on 12/29/13.
 */
public class Kerorin {

    public static void main( String args[] ) {

        LocalDate date = LocalDate.now();
        System.out.println( "today:" + date );
        System.out.println( "after five days from today:" + date.plusDays(5) );
        //ZoneId.getAvailableZoneIds().forEach(x -> System.out.println(x));
        ZonedDateTime zTime = ZonedDateTime.now(ZoneId.of("America/New_York"));
        DateTimeFormatter fmt = new DateTimeFormatterBuilder().append( DateTimeFormatter.ISO_DATE )
                .appendLiteral("-")
                .appendZoneId().toFormatter();

        System.out.println( fmt.format( zTime ) );
        System.out.println( "Converting to JST" );
        System.out.println( fmt.format( zTime.withZoneSameLocal( ZoneId.of( "Asia/Tokyo" ) ) ) );
      }

}



Java8 ラムダ

関数言語の使用者には十二分におなじみのlambda式がついにJava バージョン8で正式採用である.今まで無名クラスを書いてはコードが汚れるたびに,関数ポインタのように書ければなぁ,と思っていたのだが..これからはLambda式で綺麗にかけるようになるわけである.実にありがたい.

Lambda式を使ってリストをソート後ダンプ

import java.util.Arrays;
import java.util.List;

/**
 * Created by morinoko on 12/29/13.
 */
public class Tanukin {

    public static void main( String args[] ) {

        List<String> list = Arrays.asList( new String[]{"tanu", "tanuku", "hello"} );
        list.sort( (l,r) -> l.length() - r.length()  );
        list.forEach( s -> System.out.println( s ) );

    }

}
C++での例
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;

bool cmp(const string& l, const string& r) { return l.size() < r.size(); }
void dump(const string& s){ cout << s << endl; }

int main() {

 vector<string> v;
 v.push_back( "tanu" ); v.push_back( "tanuku" ); v.push_back( "hello" );
 sort( v.begin(), v.end(), cmp );
 for_each( v.begin(), v.end(), dump );
 
}


土曜日, 11月 16, 2013

C++ STL - Partition関数

STL algorithmのpartition関数は特定の要素をリスト中で仕分けできる便利な関数なので覚えておくとよいことが色々あるかも.以下の例はファイル名のリスト中jpegファイル名の要素とそうでない要素を分類する例.

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

static vector<string> JPEG_POSTFIX;

void init() {

 JPEG_POSTFIX.push_back(".jpg");
 JPEG_POSTFIX.push_back(".jpeg");

}

bool IsJpeg(const string& s) {
        // should use boost's to_lower, though!
 vector<string>::iterator iter;
 for(iter = JPEG_POSTFIX.begin();iter != JPEG_POSTFIX.end();iter++ ) {
  if(s.find(*iter) != string::npos)
   return true;
 }
 return false;

}

int main() {

 init();
 istringstream f("neko.jpg tako.jpeg ika.png rakko.gif fugu.jpg");
 vector<string> fileList;
 string s;
 while(getline(f,s,' ')) {
  fileList.push_back(s);
 }
 cout << "## before partitioning.." << is_partitioned( fileList.begin(),fileList.end(),IsJpeg ) << endl;
 for_each(fileList.begin(),fileList.end(),[](string& s){cout << s << " "; });
 partition(fileList.begin(),fileList.end(),IsJpeg);
 cout << endl << "## after partitioning.." << is_partitioned( fileList.begin(),fileList.end(),IsJpeg ) << endl;
 for_each(fileList.begin(),fileList.end(),[](string& s){cout << s << " "; });
 cout << endl;

 return 0;

}


月曜日, 11月 11, 2013

Java - StrSubstitutor

Apache Commons langからまた一つ便利なクラスのご紹介をさせていただきたい.
StrSubstitutorクラスは名前の通り文字列中のキーワード変換を行う.キーワードのプレフィックス・ポストフィックスの変更並びに変換後の値中のキーワードに対しての変換もサポートしている優れものである.この車輪の再発明はしないのが賢明だろう.

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

import org.apache.commons.lang3.text.StrSubstitutor;
import org.junit.Test;
import static org.junit.Assert.assertThat;
import static org.hamcrest.CoreMatchers.*;

public class StrSubstTest {

 @Test
 public void testSubst() {
  
  final String TEST_STR = "${PATTERN} cat";
  final String EXPECTED_STR = "black cat";
  
  StrSubstitutor subst = new StrSubstitutor( prepareValueMap() );
  assertThat( subst.replace( TEST_STR ), is( EXPECTED_STR ) );
  
 }
 
 @Test
 public void testSubstWithPrefix() {
  
  final String TEST_STR = "<<PATTERN>> cat";
  final String EXPECTED_STR = "black cat";
  
  StrSubstitutor subst = new StrSubstitutor( prepareValueMap(), "<<", ">>" );
  assertThat( subst.replace( TEST_STR ), is( EXPECTED_STR ) );
  
 }
 
 @Test
 public void testSubstInVariable() {
  
  final String TEST_STR = "${PATTERN} cat";
  final String EXPECTED_STR = "calico(white,black,brown) cat";
  
  StrSubstitutor subst = new StrSubstitutor( prepareValueMap2() );
  subst.setEnableSubstitutionInVariables( true );
  assertThat( subst.replace( TEST_STR ), is( EXPECTED_STR ) );
  
 }
 
 private Map<String,String> prepareValueMap() {
  
  Map<String,String> map = new HashMap<String,String>();
  map.put( "PATTERN", "black" );
  map.put( "SIZE", "big" );
  return map;
  
 }
 
 private Map<String,String> prepareValueMap2() {
  
  Map<String,String> map = new HashMap<String,String>();
  map.put( "PATTERN", "calico(${COLORS})" );
  map.put( "COLORS", "white,black,brown" );
  return map;
  
 }

}

水曜日, 10月 09, 2013

all of, any of, none of

リスト・配列要素検査の関数all_of,any_of,none_ofは是非覚えておくとよい.

#include <vector>
#include <string>
#include <iostream>
#include <algorithm>

using namespace std;

bool chk(string s) {
 return s.size() > 5;
}

int main() {

 vector<string> v;
 v.push_back("Warsaw");
 v.push_back("NewYork");

 // all of
 cout << ( all_of(v.begin(),v.end(),chk) ? "[GOOD] all good" : "some failed or all failed" ) << endl;
 v.push_back("Tokyo");
 cout << ( all_of(v.begin(),v.end(),chk) ? "[GOOD] all good" : "some failed or all failed" ) << endl;

 v.clear();
 v.push_back("Rome");
 v.push_back("Nagoya");

 // any of
 cout << ( any_of(v.begin(),v.end(),chk) ? "[GOOD] some good" : "all failed" ) << endl;
 v.erase( find( v.begin(),v.end(),"Nagoya"));
 v.push_back("Osaka");
 cout << ( any_of(v.begin(),v.end(),chk) ? "[GOOD] some good" : "all failed" ) << endl;

 // none of
 cout << ( none_of(v.begin(),v.end(),chk) ? "[GOOD] all failed" : "not all failed" ) << endl;
 v.erase(find(v.begin(),v.end(),"Osaka"));
 v.push_back("Mangalore");
 cout << ( none_of(v.begin(),v.end(),chk) ? "[GOOD] all failed" : "not all failed" ) << endl;

 return 0;

}


C++でforeach

ForeachはJavaやPythonといった他の言語で多用されている反復処理用構文である.
C++ではSTLのalgorithmがそれを提供してくれている.是非使おう.

#include <vector>
#include <string>
#include <iostream>
#include <algorithm>

using namespace std;

void show(const string s) {
 cout << s << ' ';
}

int main() {

 vector<string> v;
 v.push_back("Algonquin");
 v.push_back("Iroquois");

 for_each(v.begin(),v.end(),show);

 return 0;

}


lvalueとrvalue

C++のコンテクストでたまに見かける用語の一つがlvalueとrvalueである.
これを知らないと苦労することもあるかもしれないので是非覚えておいてほしい.

lvalue .. いわゆる変数・定数.2回以上使いまわされることもあるかもしれないデータである.
rvalue .. いわゆる代入される又は出現後即揮発するデータ.

int i = 100 * 3;

とあればiがlvalue, 100 * 3 がrvalueである.