Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Jun 6, 2010

C# : Flatten()のようなもの

RubyでいうArray#flattenに相当するメソッドがC#には無いということで、似たものを書いてみたのがこちら。System.Arrayに対する拡張メソッドとなっています。

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4.  
  5. namespace FlattenTest
  6. {
  7.     public static class ExtensionMethods
  8.     {
  9.         /// Ref.: Flatten Ruby method in C# - Stack Overflow
  10.         ///   http://stackoverflow.com/questions/197081/flatten-ruby-method-in-c
  11.         private static IEnumerable FlattenAux(this IEnumerable array)
  12.         {
  13.             foreach (var item in array)
  14.             {
  15.                 if (item is IEnumerable)
  16.                 {
  17.                     foreach (var subitem in FlattenAux((IEnumerable)item))
  18.                     {
  19.                         yield return subitem;
  20.                     }
  21.                 }
  22.                 else
  23.                 {
  24.                     yield return item;
  25.                 }
  26.             }
  27.         }
  28.  
  29.         /// Returns a one-dimensinal flattening of given array.
  30.         public static System.Array Flatten(this System.Array array)
  31.         {
  32.             var al = new ArrayList(array.Length);
  33.             foreach (var v in FlattenAux(array))
  34.                 al.Add(v);
  35.             return al.ToArray(al[0].GetType());
  36.         }
  37.     }
  38.  
  39.     class Program
  40.     {
  41.         static void Main(string[] args)
  42.         {
  43.             float[, ,] p0 = new float[3,2,2];
  44.             float[][][] p1 = new float[3][][] {
  45.                 new float[2][] { new float[2], new float[2] },
  46.                 new float[2][] { new float[2], new float[2] },
  47.                 new float[2][] { new float[2], new float[2] }
  48.             };
  49.             for (int i = 0; i < 3; ++i)
  50.                 for (int j = 0; j < 2; ++j)
  51.                     for (int k = 0; k < 2; ++k)
  52.                         p0[i, j, k] = p1[i][j][k] = 100 * i + 10 * j + k;
  53.  
  54.             float[] fp0 = (float[])p0.Flatten();
  55.             for (int i = 0; i < fp0.Length; ++i)
  56.                 Console.Write("{0} ", fp0[i]);
  57.             Console.WriteLine();
  58.  
  59.             float[] fp1 = (float[])p1.Flatten();
  60.             for (int i = 0; i < fp1.Length; ++i)
  61.                 Console.Write("{0} ", fp1[i]);
  62.             Console.WriteLine();
  63.         }
  64.     }
  65. }

May 16, 2010

乱数生成アルゴリズム WELL

Mersenne Twister (MT) の作者らによる比較的新しいアルゴリズム・ WELL (Well Equidistributed Long-period Linear) についてのメモです。
  • 原著はこちら:L'Ecuyer, Pierre; Panneton, François; Matsumoto, Makoto (2006), Improved Long-Period Generators Based on Linear Recurrences Modulo 2
  • 論文の訂正表はこちら。シフト演算の部分に関する誤りが訂正されているので必ず参考に。
  • Game Programming Gems 7 で紹介されています。記事を書いた Chris Lomont 氏 (http://www.lomont.org/) のサイトで原文が公開されています:
  • アルゴリズムの特徴は:
    • MTより計算が少しだけ重い。
    • MTは初期状態のビットパターンに0を多く含んでいると、出力する乱数のビットパターンにもしばらく0が多く含まれてしまう傾向がある。WELLはこのような状態からの脱出がMTに比べて早い。
  • C# (VS 2010) で周期 2^1024 バージョンの WELL を書いてみました:
  • 10000回の Monobit テストに対して不合格となるのは1〜2回程度。優秀だと思います。
    • System.Random を使ったら Monobit テスト 10000回に対して3000〜4000回しか合格しないケースがあることにびっくりです。

Apr 23, 2010

LINQ to XML メモ







  1. <version="1.0" encoding="utf-8"?>
  2. <game_consoles>
  3.   <ip_address_map>
  4.      <name="Xbox 360">192.168.11.2>
  5.      <name="PlayStation 3">192.168.11.3>
  6.      <name="Wii">192.168.11.4>
  7.      <name="3DO Real">192.168.11.5>
  8.      <name="DreamCast">192.168.11.6>
  9.   </ip_address_map>
  10. <game_consoles>
というXMLファイル・config.xml があるとき、「targetタグ」から「nameに3を含む」項目に次のようにしてアクセスできる:
  1. using System;
  2. using System.Linq;
  3. using System.Xml.Linq;
  4. // ...
  5.    XDocument config_xml = XDocument.Load(@".\config.xml");


  6.    var query = from c in config_xml.Descendants("target")
  7.                 where c.Attribute("name").Value.Contains("3")
  8.                 select c.Attribute("name").Value + " " + c.Value;
  9.     foreach (var q in query)
  10.     {
  11.         Console.WriteLine("{0}", q);
  12.     }


from/where/selectのあたりが LINQ (Language INtegrated Query) to XML と呼ばる仕組みを使っている部分。C# 3.0 (.NET Framework 3.5 以降) で利用可能。

ハッシュテーブルなど、別なデータ構造に入れる場合の例はこんな感じでいける:

 
  1. var platform_map = new Dictionary<string, string>();
  2. XDocument config_xml = XDocument.Load(@".\config.xml");
  3. var query = from c in config_xml.Descendants("target")
  4.                  where c.Attribute("name").Value.Contains("3")
  5.                  select new KeyValuePair<string, string>(c.Attribute("name").Value, c.Value);
  6.      foreach (var q in query)
  7.      {
  8.          platform_map[q.Key] = q.Value;
  9.      }
最初に登場した config.xml は、System.Xml.Linq 以下の XDocument などを使い次のようにして作成されたもの:





  1.     XDocument doc = new XDocument(
  2.         new XElement("game_consoles",
  3.            new XElement("ip_address_map",
  4.                 new XElement("target", new XAttribute("name", "Xbox 360"), "192.168.11.2"),
  5.                 new XElement("target", new XAttribute("name", "PlayStation 3"), "192.168.11.3"),
  6.                 new XElement("target", new XAttribute("name", "Wii"), "192.168.11.4"),
  7.                 new XElement("target", new XAttribute("name", "3DO Real"), "192.168.11.5"),
  8.                 new XElement("target", new XAttribute("name", "DreamCast"), "192.168.11.6")
  9.                 )
  10.             )
  11.         );
  12.     doc.Save(@".\config.xml");
XmlReader/XmlWriterを利用したコードに比べると格段に楽ですね。