6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

2次元の List (foreach, LINQ 使用可)

6
Posted at

System.Collections.Generic.List の2次元版みたいなクラスが欲しくなり自作しました。

要件

  • 2次元配列っぽく [x, y] で値を参照・代入可能
  • foreach 使いたい。 foreach の中で値を変更したい
  • LINQ で範囲操作したい

コード

コード全文を載せます。 List2D クラスと、 foreach 及び LINQ を使うための List2dIterator, List2dIndexer というクラスが含まれています。

List2D.cs
using System.Linq;

namespace System.Collections.Generic
{
	public class List2D<T> : IEnumerable<List2dIndexer<T>> where T : new()
	{
		public List2D(int w, int h)
		{
			mWidth = w;
			mHeight = h;

			mArr = new List<T>(w * h);

			foreach (int i in Enumerable.Range(1, w * h))
			{
				mArr.Add(new T());
			}
		}

		public T get(int x, int y) { return mArr[x + y * mWidth]; }
		public void set(int x, int y, T val) { mArr[x + y * mWidth] = val; }

		public T this[int x, int y]
		{
			set { mArr[x + y * mWidth] = value; }
			get { return mArr[x + y * mWidth]; }
		}

		public int Count { get { return mWidth * mHeight; } }
		public int Width { get { return mWidth; } }
		public int Height { get { return mHeight; } }

		public List2dIterator<T> GetEnumerator()
		{
			return new List2dIterator<T>(this);
		}

		IEnumerator<List2dIndexer<T>> IEnumerable<List2dIndexer<T>>.GetEnumerator()
		{
			return GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}

		protected int mWidth;
		protected int mHeight;
		protected List<T> mArr;
	}

	public class List2dIterator<T> : IEnumerator<List2dIndexer<T>> where T : new()
	{
		public List2dIterator(List2D<T> lst)
		{
			indexer = new List2dIndexer<T>();
			indexer.x = -1;
			indexer.y = 0;
			indexer.container = lst;
		}

		public List2dIndexer<T> Current
		{
			get
			{
				return indexer;
			}
		}

		object IEnumerator.Current
		{
			get
			{
				return Current;
			}
		}

		public void Dispose() { }

		public bool MoveNext()
		{
			++indexer.x;
			if (indexer.x == indexer.container.Width)
			{
				indexer.x = 0;
				indexer.y++;
			}
			return (indexer.y != indexer.container.Height);
		}

		public void Reset()
		{
			indexer.x = -1;
			indexer.y = 0;
		}

		List2dIndexer<T> indexer;
	}

	public class List2dIndexer<T> where T : new()
	{
		public T Value { get { return container[x, y]; } set { container[x, y] = value; } }

		public int X { get { return x; } }
		public int Y { get { return y; } }

		public bool isLastCol { get { return x == container.Width - 1; } }

		internal List2D<T> container;
		internal int x;
		internal int y;
	}
}

使用例

main.cs
using System;
using System.Collections.Generic;
using System.Linq;

public class Test
{
	public static void Main()
	{
        // 幅 20, 高さ 20 の2次元 List 作成
		var list = new List2D<int>(20, 20);

        // 中心座標 (10.0, 10.0) から距離 5 以内の点を抽出
		var query = from i in list
					where (10.0 - i.X) * (10.0 - i.X) + (10.0 - i.Y) * (10.0 - i.Y) <= 25
					select i;

        // クエリで抽出した点に 1 を代入
        // i の型は List2dIndexer<int>
		foreach(var i in query) { i.Value = 1; }

        // コンソール出力
		foreach(var i in list)
		{
			Console.Write(i.Value == 1 ? "*" : ".");

			if(i.isLastCol)
			{   // 行末で改行
				Console.WriteLine("");
			}
		}
	}
}
コンソール出力
....................
....................
....................
....................
....................
..........*.........
.......*******......
......*********.....
......*********.....
......*********.....
.....***********....
......*********.....
......*********.....
......*********.....
.......*******......
..........*.........
....................
....................
....................
....................

2次元データに対して LINQ の範囲操作ができるとコードが直感的に読めとても便利です。

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?