0

文字列をオブジェクトに変換したい。文字列は以下の構文にあります。

string nameIdPair = "name1:123\r\nname2:456\r\n";

これを変換したいオブジェクトが以下のように定義されているとします。

    public struct MyStruct
    {
        public string Name;
        public int Id;
    }

私は以下のクエリを思いついた

    var elements = nameIdPair.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries)
        .Where(p => !string.IsNullOrWhiteSpace(p))
        .Select(r => r.Split(':'))
        .Select(s => ReturnObject(s));

また、私はSQLタイプのlinqクエリを書くことを好むので、上記のクエリを分割して、以下の解決策を考え出しました

    var elements = from p in nameIdPair.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries)
                   where !string.IsNullOrWhiteSpace(p)
                   select ReturnObject(p); // Here p is string not string[]

ヘルパー関数を呼び出したくありませんでした:-

    string[] tempContainer = new string[] { };
    var elements = from p in nameIdPair.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries)
                   where (tempContainer = p.Split(':')) != null
                   select new { name = tempContainer[0], id = tempContainer[1] };

    private static object ReturnObject(string inputString)
    {
        string[] value = inputString.Split(':');
        myObject.Name = value[0];
        myObject.Id = int.Parse(value[1]);
        return myObject;
    }

最後のクエリでは、dummyContainer を使用して Where() を呼び出すだけで、dummyContainer をロードしていることに注意してください。ダミー変数や外部関数呼び出しを使用せずに最後のクエリを書き直したかったのですが、実行可能な解決策を思いつくことができませんでした。

私は以下のようなものを書くことができます

var elements = from p in nameIdPair.Split(new string[] { "\r\n", "\n" },StringSplitOptions.RemoveEmptyEntries)
               select new { name = p.Split(':')[0], id = p.Split(':')[1] };

しかし、ここでは、同じ文字列に対して何度も分割操作を行っています。一時変数を使用せずに、これを回避するにはどうすればよいですか。(from p in elements)また、呼び出されるのではなく、これらのスタイルのLINQクエリ(名前)がどのように呼び出されるかを忘れましたelements.Select()

ReturnObjectまた、関数を呼び出さずに、この投稿の最初のクエリを書き直す方法を知りたい です

さらに調べて見つけたlet

var items = from p in nameIdPair.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries)
            let r = p.Split(':')
            select new { name = r[0], id = r[1] };

ありがとう :)

4

2 に答える 2

2

let次のようなものを使用できます。

var elements = from p in nameIdPair.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries)
               let arr = p.Split(':')
               select new { name = arr[0], id = arr[1] };

MyStructそして、匿名クラスオブジェクトの代わりにそれを返したい場合は、これを試してください:

var elements = from p in nameIdPair.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries)
               let arr = p.Split(':')
               select new MyStruct { Name = arr[0], Id = int.Parse(arr[1]) };

LINQ構文に関しては、あなたが意味するのは流暢なvsクエリ式だと思います。

ここで詳細を読むことができます:LINQ - Fluent and Query Expression - Is there(s) any benefits(s) one over other?

于 2013-03-07T05:50:51.480 に答える
0

Split を 1 回だけ呼び出すソリューションを次に示します。これを LINQPad に貼り付けて試すことができます。LINQ に同等の Unzip メソッドがあるとは思いませんが、それ以外の方法を学べてうれしいです。

この解決策は、空の名前または ID エントリがないことに依存します。

void Main()
{
    string nameIdPair = "name1:123\r\nname2:456\r\n";

    var strings = nameIdPair.Split(new string[]{ "\r\n", "\r", ":" }, 
                                   StringSplitOptions.RemoveEmptyEntries);
    var structs = strings.Unzip();

    structs.Dump();
}

public struct MyStruct
{
    public string Name;
    public int Id;
}

static class Helpers
{
    public static IEnumerable<MyStruct> Unzip(this IEnumerable<string> items)
    {
        using(var en = items.GetEnumerator())
        {
            string name = null;

            while(en.MoveNext())
            {
                if(name == null){
                    name = en.Current;
                }
                else{
                    int id = int.Parse(en.Current);
                    yield return new MyStruct{Name = name, Id = id};
                    name = null;
                }
            }
        }

        yield break;
    }
}
于 2013-03-07T09:05:09.343 に答える