日曜日, 8月 23, 2015

Scala始めます

最近仕事でどうやらSparkを使い始めることになりそう.
Sparkの調査過程で明らかになったのは,JavaでSparkのコードを書くべきでなく,scalaで書くべきだということ.(既にSparkを使われている方々にとっては当然のことだと思うが).

まず第一にコードの量が違いすぎる.JavaでのSparkコードは冗長である一方Scalaでのコードは短くエレガントだ.

問題は私自身のscala経験が無いので一から勉強である.
C++, bash, Javaそしてgroovyを主に使ってきた私にしてもscala習得はかなり歯ごたえがありそうな気がする.

以下のコードは一応私にとってhello worldのようなもの.年末までくらいに自身がどれくらいのscalaコードを書けるようになっているか楽しみである.


import scala.util.Random

object Test {
  def main(args: Array[String]) {
    val r = new Random()
    // does not work
    def l1 = r.shuffle((0 to 20).toList)
    def l2 = r.shuffle((0 until 20).toList)
    l1.foreach { it => println(it) }

    println(l1 sameElements l2)
  }
}

土曜日, 3月 28, 2015

リストのループ検出

リストのループ重複検出をするコードを書いてください,という質問は候補者が勉強をしてきたかどうかを見るのに加減の良い問題だと,昨今のインタビューをしていて思った次第である.

 様々な解の仕方があるが,やはりウサギさんとカメさんを期待するだろう.
#include <iostream>

class Node {
// to make code simpler, members are public
public:
 int _data;
 Node* _next;
 Node(int data) :_data(data) {
  _next = NULL;
 }
 ~Node(){}
 Node(Node& n) {
  _data = n._data;
  _next = n._next;
 }
 Node& operator=(Node& n) {
  _data = n._data;
  _next = n._next;
  return *this;
 }
};

void iterate(Node* root) {
 Node* p = root;
 int cnt = 0;
 while (p) {
  std::cout << p->_data << std::endl;
  p = p->_next;
  if (cnt++ >= 100) {
   std::cerr << "!!!! potential loop found" << std::endl;
   return;
  }
 }
}

void add(Node* root, int val) {
 Node* n = new Node(val);
 Node* p = root;
 while (p->_next) {
  p = p->_next;
 }
 p->_next = n;
}

bool detectLoop(Node* root) {
 Node* slow_ptr = root;
 Node* fast_ptr = root;
 while (slow_ptr && fast_ptr && fast_ptr->_next) {
  slow_ptr = slow_ptr->_next;
  fast_ptr = fast_ptr->_next->_next;
  std::cout << slow_ptr->_data << ":" << fast_ptr->_data << std::endl;
  if (slow_ptr == fast_ptr) {
   return true;
  }
 }
 return false;
}

int main() {
 Node r(10);
 add(&r, 32);
 add(&r, 64);
 add(&r, 128);
 // simulate loop here
 r._next->_next->_next->_next = r._next;
 iterate(&r);
 std::cout << "loop exists?" << (detectLoop(&r) ? "TRUE" : "FALSE") << std::endl;
 return 0;
}

日曜日, 1月 18, 2015

guice

現在のプロジェクトからguiceを使うことになったが,これはなかなかの優れものだと思う.
今まで使ったDIフレームワークと比べても,コードを簡潔に短くことが出来るようになったと思う.
  以下の例はFTPでファイルを送信するロジックを仮実装した例.コンフィグのバインドの例は決して真似をせぬ様.あくまでguiceの基本バインドの例である.


FileTransmit.java
ackage org.tanuneko;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;


public class FileTransmit {

    public static void main(String args[]) {

        String[] myArgs = {"/home/neko32", "tako.log", "640"};
        Config c = new AppConfig(myArgs);

        Injector injector = Guice.createInjector(new AbstractModule() {
            @Override
            protected void configure() {
                bind(FileSenderIF.class).to(FTPFileSender.class);
                bind(Config.class).toInstance(c);
            }
        });

        FileTransmitProgram ft = injector.getInstance(FileTransmitProgram.class);
        ft.run();
    }

    class MyAppConfig extends Config {
        MyAppConfig(String[] args) {
            // do not do this in product code
            super.logFileLocation = args[0];
            super.logFileName = args[1];
            super.maxFileSize = Integer.parseInt(args[2]);
        }
    }
}



FileTransmitProgram.java
package org.tanuneko;

import com.google.inject.Inject;

public class FileTransmitProgram {

    @Inject
    private FileSenderIF sender;
    @Inject
    private Config conf;


    public void run() {
        sender.setLogging(conf.getLogFileLocation(), conf.getLogFileName());
        sender.setFileMaxFileSize(conf.getMaxFileSize());
        sender.send("ABC", "DATA");
    }
}


FTPFileSender.java
package org.tanuneko;

public class FTPFileSender implements FileSenderIF {

    private int maxFileSize = -1;

    public void setLogging(String logLocation, String fileName) {
        System.out.println(String.format("Setting logs[%s/%s]", logLocation, fileName));
    }

    public void setFileMaxFileSize(int maxFileSize) {
        int prevMax = maxFileSize;
        this.maxFileSize = maxFileSize;
        System.out.println(String.format("max file size has changed from %d to %d", prevMax, this.maxFileSize));
    }

    @Override
    public void send(String fileName, String data) {
        System.out.println(String.format("file %s(%s) was sent via FTP", fileName, data));
    }
}

日曜日, 1月 11, 2015

Java8 - Function::compose

Java8のFunctionクラスのcompose()メソッドを使えば,簡単にメソッドチェインを実装できる.
上手く使えばコードをかなり簡潔にできるだろう.以下のコードは3つの文字列操作フィルタをチェインして適用させた例.

package org.tanuneko;

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

public class FuncComposer {

    public FuncComposer() {
    }

    public void run() throws Exception {
        Function<String,String> addPrefixFilter = x -> "***" + x;
        Function<String,String> addPostfixFilter = x -> x + "***";
        Function<String,String> toLowerCaseFilter = x -> x.toLowerCase();
        String base = "WOW";

        Function<String,String> composedFilter =
        Stream.of(addPrefixFilter, addPostfixFilter, toLowerCaseFilter)
                .reduce((func, nxt)->func.compose(nxt))
                .orElseGet(Function::identity);

        System.out.println(composedFilter.apply(base));
    }


    public static void main(String args[]) throws Exception {
        FuncComposer c = new FuncComposer();
        c.run();
    }
}

ElasticSearch IntegrationTest

ElasticSearch IntegrationTestを使えば,メモリ上での仮想クラスタ上で単体テストを走らせることができる優れものだが,あまりサンプルコードが見つからない気がする.


package org.tanuneko;

import org.apache.commons.io.FileUtils;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.query.FilterBuilders;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
import org.junit.Test;

import java.io.File;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Map;
import java.util.function.Function;

import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.hamcrest.core.Is.is;


@ClusterScope(scope= ElasticsearchIntegrationTest.Scope.SUITE,numDataNodes=2)
public class ESIntegrationTest extends ElasticsearchIntegrationTest {

    private static final String INDEX_NAME = "tanuapp";
    private static final String DOCTYPE_NAME = "posting_msg";
    private static final String TODAY_DATE_STR = new SimpleDateFormat("yyyy-MM-dd").format(new Date());

    @Test
    public void testSearch() throws Exception {
        createIndex(INDEX_NAME);
        client().admin().indices().preparePutMapping(INDEX_NAME)
                .setType(DOCTYPE_NAME)
                .setSource(readMappingFile(DOCTYPE_NAME + "_mappings.json"))
                .execute().actionGet();

        assertThat(indexDoc(INDEX_NAME, DOCTYPE_NAME, "1", "neko32", "hellou").isCreated(), is(true));
        assertThat(indexDoc(INDEX_NAME, DOCTYPE_NAME, "2", "ushi", "poooo").isCreated(), is(true));
        assertThat(indexDoc(INDEX_NAME, DOCTYPE_NAME, "3", "neko64", "ka-kakinkin ka-kinkin").isCreated(), is(true));

        flushAndRefresh(INDEX_NAME);
        ensureGreen(INDEX_NAME);
        assertThat(indexExists(INDEX_NAME), is(true));

        GetResponse resp = client().prepareGet(INDEX_NAME, DOCTYPE_NAME, "3")
                .execute()
                .actionGet();

        Map source = resp.getSource();
        assertThat((String)source.get("user"), is("neko64"));
        assertThat((String)source.get("message"), is("ka-kakinkin ka-kinkin"));
        final String postedDate = (String)source.get("postDate");
        Function isSameDate = x -> x.startsWith(TODAY_DATE_STR);
        assertTrue(isSameDate.apply(convertToGMT(postedDate)).booleanValue());

        SearchResponse searchResp = client().prepareSearch(INDEX_NAME)
                .setTypes(DOCTYPE_NAME)
                .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
                .setQuery(QueryBuilders.fuzzyLikeThisFieldQuery("user").likeText("neko50"))
                .setPostFilter(FilterBuilders.idsFilter(DOCTYPE_NAME).ids("1"))
                .execute()
                .actionGet();

        assertThat(searchResp.getHits().getHits().length, is(1));
        assertThat(searchResp.getHits().getAt(0).getSource().get("user"), is("neko32"));
    }


    private String readMappingFile(final String fileName) throws Exception {
        return FileUtils.readFileToString(new File(ESIntegrationTest.class.getClassLoader().getResource(fileName).getPath()));
    }

    private String convertToGMT(String dateStr) {
        return LocalDateTime.parse(dateStr.substring(0,dateStr.length()-1)).toString();
    }

    private IndexResponse indexDoc(final String idxName,
                                    final String docName,
                                    final String id,
                                    final String user,
                                    final String msg) throws Exception {
        return client().prepareIndex(INDEX_NAME, DOCTYPE_NAME)
                .setSource(genMsg(user, msg))
                .setId(id)
                .execute().actionGet();
    }

    private XContentBuilder genMsg(String user, String msg) throws Exception {
        return jsonBuilder().startObject()
                .field("user", user)
                .field("postDate", new Date())
                .field("message", msg)
                .endObject();
    }
}


火曜日, 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 ) );
}
}