今日も引き続き挑戦してました。18問目まで終了。
12問目がなかなか計算時間短縮が難しい。
技術ブログを始めたくてなんとなくスタートです。 たぶん長続きしないはず…
Project Eulerなるものを知った。数学の問題をプログラムで解くらしい。
おもしろそうなので、登録してみた。
#そういえば、TopCoderに登録してそのままなことを思い出した。
http://projecteuler.net/
日本語のWikiもあり、問題も日本語化されているようだ。<やった。
http://odz.sakura.ne.jp/projecteuler/index.php?Project%20Euler
番号が若いうちは比較的簡単。出来るだけLinqを使って書くように心がける。
#でもLinqだと無駄が出やすい気がする。スピード重視なら、手続き指向になるのかなぁ。
とりあえず、今日は8問目まで。
Entity Framework4では、外部キーをスカラプロパティーとして公開することが出来ます。
外部キーの使用 (Entity Framework)
http://msdn.microsoft.com/ja-jp/library/ee794150.aspx
でも、追加方法がよくわからずはまったので備忘録。
①追加からアソシエーションを選択すること。
(ツールボックスからではダメ。ここではまった。)
②外部キープロパティーの追加にチェックを付ける
③プロパティーが追加されます。
ところで、追加されたプロパティーが、どのアソシエーションに関連しているかを確認する方法がない?
長らくx64環境からMDBファイルにアクセスすることが出来なかった。
(正しくは、32bitアプリとしてWOW64上で動作する様に、ビルド構成としてx86を指定する必要があった。)
Office2010(x64)をインストールすることにより、64bitのアプリケーションでもMDBファイルにアクセスできるようになる。ConnectionStringで”Microsoft.ACE.OLEDB.12.0”するだけである。
データ接続コンポーネントも、今はベータがとれていないが、そのうちベータがとれるだろう。
(2010 Office system Beta ドライバ: データ接続コンポーネント)
http://www.microsoft.com/downloads/details.aspx?familyid=C06B8369-60DD-4B64-A44B-84B371EDE16D&displaylang=ja
これにより、32bitでは"Microsoft.JET.OLEDB.4.0"、64bitでは"Microsoft.ACE.OLEDB.12.0”と接続文字列を切り替えることにより、どちらの環境でも動作させることが可能になる。
※32bitでも下記ドライバをインストールすれば、"Microsoft.ACE.OLEDB.12.0”で接続が可能。
2007 Office system ドライバ: データ接続コンポーネント
http://www.microsoft.com/downloads/details.aspx?FamilyId=7554F536-8C28-4598-9B72-EF94E038C891&displaylang=ja
なお、32bitで動作しているか64bitで動作しているかは、IntPtr.Sizeで判定が可能だそうだ。
(とあるコンサルタントのつぶやき:Part 2. .NET Framework 2.0 アプリケーションの 64 ビット対応)
http://blogs.msdn.com/nakama/archive/2008/11/06/part-2-net-framework-2-0-64.aspx
なお、アプリケーションの内部から、現在自分が 64 ビット/32 ビットどちらで動作しているのかを知る一番簡単な方法は、IntPtr.Size プロパティをチェックするというものです。
- IntPtr.Size = 8 の場合は 64 ビットモードでプロセスが動作している。
- IntPtr.Size = 4 の場合は 32 ビットモードでプロセスが動作している。
Visual Studio 2010(.NET Framework 4)より、PLINQ (Parallel LINQ)が追加され、並列処理が簡単にできるようになっています。
10 行でズバリ !! 並列プログラミング - PLINQ (C#)より
PLINQ は LINQ によるデータ コレクションに対するクエリ処理を並列化するためのものであり、PLINQ を使用することで LINQ クエリの Select 句や Where 句で実行されるロジックを容易に並列処理化することが可能です。PLINQ の機能は ParallelEnumerable クラス (System.Linq.ParallelEnumerable) の拡張メソッドとして提供されており、LINQ クエリの処理対象データ コレクションに対して ParallelEnumerable クラスの拡張メソッドの呼び出しを追加するだけでデータ コレクションへの処理を並列化し、マルチプロセッサー/マルチコア CPU の処理能力を活用して処理時間を短縮することができます。
と言うわけで、先日の重いLinq構文を何とか出来ないかとあちこちにAsParallelを追加してみました。
が、Aggregate構文を途中で使用しているためか、追加前より速くなることはありませんでした。
残念。
0~9までの数字のカードがN枚ある。同じ数字のカードは1枚とは限らない。
そこから、M枚使用しM桁の整数を作るとき、小さい方から数えi番目の数値は何か?
※先頭桁に0はこないものとする。
という問題が与えられた場合、これを効率よく説くにはどうすればよいか?
とりあえず、効率よくという部分は無視して、順列を作成して前から数えてみた。順列を作成するに当たりLinqを使用しているサイトが見つかったので、利用にさせていただいた。
http://d.hatena.ne.jp/taguo/20080722/1216745650
class Program
{
static void Main(string[] args)
{
int[] array = {0,0,1,2,2,3};
var result = array.GetPermutation(4)
.Where(x => x.ElementAt(0) != 0)
.Select(x => string.Join("", x.Select(i => i.ToString()).ToArray()))
.Distinct();
result = result.Skip(10).Take(1);
foreach (var item in result)
{
Console.WriteLine(item);
}
}
}
public static class Util
{
public static IEnumerable<IEnumerable<T>> GetPermutation<T>(this IEnumerable<T> source, int count)
{
return Enumerable.Range(0, count)
.Select(_ => source)
.Select(et => et.Select((t, i) => new { t, i }))
.Aggregate(Enumerable.Repeat(Enumerable.Repeat(new { t = default(T), i = default(int) }, 0), 1)
, (ac, et) => from a in ac
from t in et
where !a.Contains(t)
select a.Concat(Enumerable.Repeat(t, 1)))
.Select(ea => ea.Select(a => a.t));
}
}
実は、delegateの非同期呼出は使ったことがなかったり…
というわけで、MultiCastDelegateといえどもターゲットが複数あるとダメなのは初めて知りました。
出来ても良さそうなのにね。
delegateは、メソッド情報(Methodプロパティー)を呼びメソッドの定義されるインスタンスの情報(Targetプロパティー)を持ち、それを同期または非同期に呼び出すことができる。
というわけで、まずは同期呼出から。とっても基本的な使い方。
delegate void Hoge(string str);
static void Main(string[] args)
{
Hoge hoge = null;
hoge = Console.WriteLine;
hoge("AAA");
hoge.Invoke("AAA");
}
delegateで宣言すると、MultiCastDelegateのサブクラスとなるので、常にInvocation Listを作ることが可能。
static void Main(string[] args)
{
Hoge hoge = null;
hoge = Console.WriteLine;
hoge += delegate(string str)
{
Console.WriteLine(str.ToLower());
};
hoge("AAA");
}
メソッドの引数は同じオブジェクトが順番に渡されるため、1番目のメソッドで行われた変更を2番目のメソッドへと引き継ぐ。MultiCastDelegateの場合、最後のメソッドの戻り値以外は捨てられるので、引数のオブジェクトを通してしか情報の伝達ができない。
class Program
{
//戻値の型 デリゲートの型名 引数の型
delegate void Hoge(Class c);
static void Main(string[] args)
{
Hoge hoge = null;
hoge += AAA;
hoge += AAA;
hoge += AAA;
hoge += AAA;
hoge(new Class());
}
static void AAA(Class c)
{
Console.WriteLine(c.MyProperty);
++c.MyProperty;
}
}
class Class : Interface
{
public int MyProperty { get; set; }
}
Interfaceは参照型だったよな。と思い確認。
class Program
{
static void Main(string[] args)
{
Struct s = new Struct();
s.MyProperty = 1;
Interface i = s;
i.MyProperty = 2;
Interface i2 = i;
i2.MyProperty = 3;
Console.WriteLine("s :{0}", s.MyProperty);
Console.WriteLine("i :{0}", i.MyProperty);
Console.WriteLine("i2:{0}", i2.MyProperty);
}
}
interface Interface
{
int MyProperty { get; set; }
}
struct Struct : Interface
{
public int MyProperty { get; set; }
}
正解。
つまり、Interface型に代入する際にボックス化が行われているということ。
class Program
{
static void Main(string[] args)
{
var val = new Struct();
var val2 = new Class();
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 1000000000; i++)
{
object obj = val;
}
Console.WriteLine("struct -> object :" + sw.Elapsed);
sw.Reset();
sw.Start();
for (int i = 0; i < 1000000000; i++)
{
Interface obj = val;
}
Console.WriteLine("struct -> Interface:" + sw.Elapsed);
sw.Reset();
sw.Start();
for (int i = 0; i < 1000000000; i++)
{
var obj = val;
}
Console.WriteLine("struct -> struct :" + sw.Elapsed);
sw.Reset();
sw.Start();
for (int i = 0; i < 1000000000; i++)
{
Interface obj = val2;
}
Console.WriteLine("class -> Interface:" + sw.Elapsed);
sw.Reset();
sw.Start();
for (int i = 0; i < 1000000000; i++)
{
object obj = val2;
}
Console.WriteLine("class -> object :" + sw.Elapsed);
sw.Reset();
sw.Start();
for (int i = 0; i < 1000000000; i++)
{
var obj = val2;
}
Console.WriteLine("class -> class :" + sw.Elapsed);
}
}
interface Interface
{
int MyProperty { get; set; }
}
struct Struct : Interface
{
public int MyProperty { get; set; }
}
class Class : Interface
{
public int MyProperty { get; set; }
}
boxing(ボックス化)とは、値型を参照型であるobjectに変換する機能。
これにより、参照型であるobjectに値型を代入することができる。
ただし、パフォーマンス上の注意が必要。Generic型を使用することにより、boxingを防ぐことができる。
static void Main(string[] args)
{
var val = new Struct();
var val2 = new Class();
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 1000000000; i++)
{
object obj = val;
}
Console.WriteLine("struct -> object:" + sw.Elapsed);
sw.Reset();
sw.Start();
for (int i = 0; i < 1000000000; i++)
{
var obj = val;
}
Console.WriteLine("struct -> struct:" + sw.Elapsed);
sw.Reset();
sw.Start();
for (int i = 0; i < 1000000000; i++)
{
object obj = val2;
}
Console.WriteLine("class -> object:" + sw.Elapsed);
sw.Reset();
sw.Start();
for (int i = 0; i < 1000000000; i++)
{
var obj = val2;
}
Console.WriteLine("class -> class :" + sw.Elapsed);
var list = new List<Struct>(100000000);
var list2 = new List<Class>(100000000);
sw.Reset();
sw.Start();
for (int i = 0; i < 100000000; i++)
{
list.Add(val);
}
Console.WriteLine("generic list <- struct:" + sw.Elapsed);
sw.Reset();
sw.Start();
for (int i = 0; i < 100000000; i++)
{
list2.Add(val2);
}
Console.WriteLine("generic list <- class :" + sw.Elapsed);
var list3 = new ArrayList(100000000);
var list4 = new ArrayList(100000000);
sw.Reset();
sw.Start();
for (int i = 0; i < 100000000; i++)
{
list3.Add(val);
}
Console.WriteLine("normal list <- struct:" + sw.Elapsed);
sw.Reset();
sw.Start();
for (int i = 0; i < 100000000; i++)
{
list4.Add(val2);
}
Console.WriteLine("normal list <- class :" + sw.Elapsed);
}
struct Struct
{
public int MyProperty { get; set; }
}
class Class
{
public int MyProperty { get; set; }
}
EffectiveC#を読んで、基本に立ち返ってみた。
(参照渡)
class Program
{
static void Main(string[] args)
{
var val = new Class();
var val2 = val; //参照渡し
val.MyProperty = 100;
//100 が表示される
Console.WriteLine(val2.MyProperty);
}
}
class Class
{
public int MyProperty { get; set; }
}
(値渡)
class Program
{
static void Main(string[] args)
{
var val = new Struct();
var val2 = val; //値渡し
val.MyProperty = 100;
//0 が表示される
Console.WriteLine(val2.MyProperty);
}
}
struct Struct
{
public int MyProperty { get; set; }
}
DbProviderFactoryから作成できる、DbDataSourceEnumerator。一度も使ったことがなかったので、使ってみた。
if (factory.CanCreateDataSourceEnumerator)
{
DbDataSourceEnumerator dse = factory.CreateDataSourceEnumerator();
dataGridView1.DataSource = dse.GetDataSources();
}
Commonに必要か?
前回の続き(?)。
Providerに依存しないコードを書いてみた。
ConnectionStringSettings css = ConfigurationManager.ConnectionStrings["MyConnection"];
DbProviderFactory factory = DbProviderFactories.GetFactory(css.ProviderName);
DbConnectionStringBuilder sb = factory.CreateConnectionStringBuilder();
sb.ConnectionString = css.ConnectionString;
//この辺はProviderに依存するよなぁ
sb.Add("Password", "xxxx");
using (DbConnection connection = factory.CreateConnection())
{
connection.ConnectionString = sb.ConnectionString;
connection.Open();
//factory.CreateCommand()でもいいけど、こっちの方が素直な気がする。
DbCommand command = connection.CreateCommand();
//ここも依存することが多いよね。
command.CommandText = "SELECT * FROM TABLE1 WHERE ID = ?";
DbParameter p = factory.CreateParameter();
p.DbType = DbType.Int32;
p.Value = 1;
command.Parameters.Add(p);
using (DbDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
reader.GetInt32(0);
}
}
}
DbProviderFactoryを使用することにより、データプロバイダに依存しない実装が可能。で、備忘録
使用可能なProvider一覧を取得DbProviderFactories.GetFactoryClasses();
ApplicationでDataProviderを追加したい場合は、app.configに設定することで追加可能。 例えば、PostgreSQLの場合は、↓の様に設定。
<system.data> <DbProviderFactories> <add name="Npgsql Data Provider" invariant="Npgsql" description=".Net Framework Data Provider for PostgreSQL" type="Npgsql.NpgsqlFactory, Npgsql, Version=2.0.8.0, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7" /> </DbProviderFactories> </system.data>
app.configよりConnectionStringを取得してDbProviderFactoryを作成
ConnectionStringSettings css = ConfigurationManager.ConnectionStrings["MyConnection"]; DbProviderFactory factory = DbProviderFactories.GetFactory(css.ProviderName);
あとは、factory.CreateXXXXX()で作成し放題!
以前より、Linqを利用しMDBファイルにアクセスする方法をもさくしている。
いろいろ検索しているうちに、ADO.NET Entity Frameworkにて、独自のProviderを実装する方法を紹介しているページを発見。
http://blogs.msdn.com/adonet/archive/2007/03/16/ado-net-orcas-sample-provider.aspx
#だが英語
MSDNのCode Gallery内で、サンプルとOracle版は公開されているようだ。
http://code.msdn.microsoft.com/EFSampleProvider
http://code.msdn.microsoft.com/EFOracleProvider
これを参考にOleDBをWrappeingするProviderを作ればいいのか?
誰か作っててもいいのに…
世間では.NET4.0がリリースされようとしている昨今。今更ながらLinq to SQL の勉強です。
Linq to SQLは、ADO.NET Entity Frameworkに取って代わられるとか言われてますが、気にしない。
(参考リンク)
http://msdn.microsoft.com/ja-jp/library/bb425822.aspx
上記ページでどうしても納得いかない箇所が…。DataContextにTable<T>を定義して、それに対してLinqでクエリを投げている箇所。
public partial class Northwind : DataContext
{
public Table<Customer> Customers;
public Table<Order> Orders;
public Northwind(string connection): base(connection) {}
}
Northwind db = new Northwind("c:\\northwind\\northwnd.mdf");
var q =
from c in db.Customers
where c.City == "London"
select c;
foreach (var cust in q)
Console.WriteLine("id = {0}, City = {1}",cust.CustomerID, cust.City);
DataContextにTable<Customer>をフィールドとして定義しているだけで、いつの間にか値が代入されている。おそらく、コンストラクタ内でリフレクションを使用して代入しているのだろうが、わかりにくい。
前々からずっと気になっていたんですが、なかなか試す機会がなかったで連休を利用してチャレンジです。
用意したもの
始める
上記をインストールすると、VisualStudioにSilverlight用のプロジェクトテンプレートが追加されていました。
とりあえず、Silverlightナビゲーションアプリケーションを選択(サンプルプロジェクトぽかったので)。
するとダイアログが出てきて、何かを尋ねます。意味がわかってないので、デフォルトで。
作成されたプロジェクトを、そのまま実行した結果。をを、うごいてますな。
画面レイアウトはBlendで編集するとのことなので、先ほどVisualStudioで作成されたプロジェクトをBlendで開いてみる。
そうすると、なぜがMainPage.xamlがエラーをはいています。なぜ?
原因は、XAMLに書かれた日本語が文字化けして、"(ダブルクォーテーション)が消えてることでした。
文字コードが違うみたい。どこかで文字コードを設定する箇所があるのでしょうか?
で、ここで詰まってます。先は長い。
(追記)
Blend上でファイルを右クリック→外部で編集。メモ帳でファイルが開くので、そのまま上書き保存。
そうすると、Blend側で上記ダイアログが表示され、ファイルの再読み込みを促される。
はいをクリックすると、エラーが解決する。一度解決したファイルは次からは正しく表示される。
XAMLファイルの数だけ上書き作業を行うとOK?なのかも。
なぜでしょうね。
Linqから使用しやすい数列を作成する勉強第1弾。
今更ながらなLinqなのですが、.NET Framework3.5はまだ仕事で使えない(※)ので、まだまだ詳しくありません。
ちょっとずつ勉強予定です。
public static IEnumerable<decimal> Fibonacci()
{
decimal previous = 0M;
decimal current = 1M;
while (true)
{
yield return current;
current += previous;
previous = current - previous;
}
}として、
var fs = from f in EnumerableUtil.Fibonacci()
where f % 3 == 0
select f;
foreach (var item in fs)
{
Console.WriteLine(item);
}こんな感じかね。
※Windows2000上で、.NET Framework3.5が動かないからなぁ。