C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[3]: Linqを使うとどこまで変更できますか?


(過去ログ 141 を表示中)

[トピック内 5 記事 (1 - 5 表示)]  << 0 >>

■82682 / inTopicNo.1)  Linqを使うとどこまで変更できますか?
  
□投稿者/ 夜叉丸 (41回)-(2017/01/26(Thu) 15:44:54)

分類:[.NET 全般] 

現在 LINQ を使っていろいろ試してどこまでできるのかテストしているのですが、


sourceに、2個ずつ組の文字列が連続して存在しています。
"AB" + "CD" + … + "IJ" → "ABCDEFGHIJ"
dest にある複数の文字列 "CD", "GH" のどちらかが source に含まれている場合に True を返すというものを作りました。


   string source = "ABCDEFGHIJ";
   string dest = "CD,GH";

   List<string> slist = new List<string>();
   for(int ilstnum = 0; ilstnum < source.Length; ilstnum += 2) slist.Add(source.Substring(ilstnum, 2));

   List<string> dlist = new List<string>(dest.Split(','));


   bool find = false;
   for(int idnum = 0; idnum < dlist.Count; idnum++)
   {
    find = slist.Any(a => a == dlist[idnum]);
    if(find) break;
   }

   MessageBox.Show(find.ToString());

このコードは全体的にLINQ を使用してもっと短いコードで表現できますか?

もし可能であれば次に

source, dest ともに、2個ずつ組の文字列が連続して存在しています。
source : "AB" + "CD" + … + "IJ" → "ABCDEFGHIJ"
dest : "CD" + "IJ", "GH" → "CDIJ", "GH"

dest にある文字 "CDIJ" → "CD" + "IJ" の両方ともまたは, "GH" のどちらかが source に含まれている
場合 True を返すというものを作ります。

  private bool Check()
  {
   string source = "ABCDEFGHIJ";
   string dest = "CDIJ,GH";

   // "ABCDEFGHIJ" → "AB", "CD", "EF", "GH", "IJ" に分割
   List<string> slist = new List<string>();
   for(int ilstnum = 0; ilstnum < source.Length; ilstnum += 2) slist.Add(source.Substring(ilstnum, 2));

   // "CDIJ", "GH" → "CDIJ", "GH" に分割
   List<string> dlist = new List<string>(dest.Split(','));

   bool find = false;
   for(int idnum = 0; idnum < dlist.Count; idnum++)
   {
    // idnum=0: "CDIJ" → "CD", "IJ"
    // idnum=1: "GH" → "GH"
    List<string> dsublist = new List<string>();
    for(int ilstnum = 0; ilstnum < dlist[idnum].Length; ilstnum += 2) dsublist.Add(dlist[idnum].Substring(ilstnum, 2));

    find = false;
    for(int idsubnum = 0; idsubnum < dsublist.Count; idsubnum++)
    {
     find = slist.Contains(dsublist[idsubnum]);
     if(!find) break;
    }
    if(find) break;
   }
   return (find);
  }

LinQ を使うとどこまで変更できるのしょうか?
引用返信 編集キー/
■82684 / inTopicNo.2)  Re[1]: Linqを使うとどこまで変更できますか?
□投稿者/ shu (955回)-(2017/01/26(Thu) 16:35:25)
2017/01/27(Fri) 08:16:02 編集(投稿者)
No82682 (夜叉丸 さん) に返信

VBですが、最初のは

        Dim srcstr = "ABCDEFGHIJ"
        Dim desstr = "CD,GH"

        Dim res = (From idx In Enumerable.Range(0, srcstr.Length \ 2)
                   Select a = srcstr.Substring(idx * 2, 2) Join
                   c In desstr.Split(","c) On a Equals c).Count > 0


でいけると思います。入力が規則にしたがっている必要があるので、文字数チェックを事前に行った方がよいかもしれません。

次の例はこれを応用して実装するのは困難かと思います。


#追記:Count判定よりAnyの方が見やすく意味がわかりやすいらしいので

        Dim srcstr = "ABCDEFGHIJ"
        Dim desstr = "CD,GH"

        Dim res = (From idx In Enumerable.Range(0, srcstr.Length \ 2)
                   Select a = srcstr.Substring(idx * 2, 2) Join
                   c In desstr.Split(","c) On a Equals c).Any
も載せておきます。

引用返信 編集キー/
■82689 / inTopicNo.3)  Re[1]: Linqを使うとどこまで変更できますか?
□投稿者/ 魔界の仮面弁士 (1087回)-(2017/01/26(Thu) 18:56:07)
2017/01/27(Fri) 09:03:14 編集(投稿者)

No82682 (夜叉丸 さん) に返信
> Linqを使うとどこまで変更できますか?
> 現在 LINQ を使っていろいろ試してどこまでできるのかテストしているのですが、
> LinQ を使うとどこまで変更できるのしょうか?

"LinQ" だとアイドルグループの名前になってしまうので、
すべて大文字で "LINQ" と書いた方が良いですよ。(^^;
https://msdn.microsoft.com/ja-jp/library/bb308959.aspx


> source, dest ともに、2個ずつ組の文字列が連続して存在しています。
> source : "AB" + "CD" + … + "IJ" → "ABCDEFGHIJ"
> dest : "CD" + "IJ", "GH" → "CDIJ", "GH"

2 文字ずつで分断するための拡張メソッドを用意しておくと便利ですよ。


string source = "ABCDEFGHIJ";
string dest = "CDIJ,GH";

// 2 文字単位で分割 ⇒ {"AB", "CD", "EF", "GH", "IJ"}
var contents = source.Chunk(2);

// 条件単位で分割 ⇒ { { "CD", "IJ"}, {"GH"} }
var conditions = dest.Split(',').Select(_ => _.Chunk(2));

// 合致判定
bool found = conditions.Any(_ => _.All(contents.Contains));

//
// 可読性を無視して一行で書いてみました
// bool found = dest.Split(',').Select(x => x.Chunk(2)).Any(y => y.All(z => source.Chunk(2).Contains(z)));
//


上記で利用した「Chunk メソッド」の実装例です。

static class StringExtensions
{
  public static IEnumerable<string> Chunk(this string source, int length)
  {
    IEnumerable<char> e = source;
    while (e.Any())
    {
      yield return new String(e.Take(length).ToArray());
      e = e.Skip(length);
    }
  }
}


◇追記◇

もし拡張メソッドを自作したくないのであれば、 No82684 を真似て
 var contents = source.Chunk(2);
の部分を
 var contents = Enumerable.Range(0, source.Length / 2).Select(i => source.Substring(i * 2, 2));
のように置き換えることもできます。
(Substring 版だと、source の文字数が奇数だった場合に対応できなくなりますが)
引用返信 編集キー/
■82696 / inTopicNo.4)  Re[2]: Linqを使うとどこまで変更できますか?
□投稿者/ 魔界の仮面弁士 (1091回)-(2017/01/27(Fri) 12:59:38)
No82689 (魔界の仮面弁士) に追記
>> 現在 LINQ を使っていろいろ試してどこまでできるのかテストしているのですが、
> // 可読性を無視して一行で書いてみました
> // bool found = dest.Split(',').Select(x => x.Chunk(2)).Any(y => y.All(z => source.Chunk(2).Contains(z)));

調子に乗って、C# 2005 でも書いてみました。
System.Core.dll を参照設定した上で「using System.Linq;」が必要です。


ラムダ式が使えないので、匿名メソッドで代用。
Enumerable の拡張メソッドが使えないので、通常のメソッド呼び出しで代用。
var 宣言が使えないので、変数の型を明示指定して代用。
型推論が不十分なので、型パラメータを明示指定して回避。



string source = "ABCDEFGHIJ";
string dest = "CDIJ,GH";


bool found =
  Enumerable.Any<IEnumerable<string>>
  (
    Enumerable.Select<string, IEnumerable<string>>
    (
      dest.Split(','),  // "CDIJ,GH" ⇒ {"CDIJ", "GH"}
      delegate(string str)
      {
        // "CDIJ" ⇒ {"CD", "IJ"}、"GH" ⇒ {"GH"}
        return Enumerable.Select<int, string>
        (
          Enumerable.Range(0, str.Length / 2),
          delegate(int i) { return str.Substring(i * 2, 2); }
        );
      }
    ),
    delegate(IEnumerable<string> conditions)
    {
      return Enumerable.All<string>
      (
        conditions,  // {"CD", "IJ"} または {"GH"}
        delegate(string keyValue)
        {
          return Enumerable.Contains<string>
          (
            // "ABCDEFGHIJ" ⇒ {"AB", "CD", "EF", "GH", "IJ"}
            Enumerable.Select<int, string>
            (
              Enumerable.Range(0, source.Length / 2),
              delegate(int i) { return source.Substring(i * 2, 2); }
            ),
            keyValue  // "CD" または "IJ"、あるいは "GH"
          );
        }
      );
    }
  );
引用返信 編集キー/
■82758 / inTopicNo.5)  Re[3]: Linqを使うとどこまで変更できますか?
□投稿者/ 夜叉丸 (42回)-(2017/02/02(Thu) 09:23:45)
ありがとうございました。

全部というわけにはいかないので、つけるところは使っていきたいと思います。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -