スペースで区切られた単語の文字列があります。単語の長さに基づいて文字列を単語のリストに分割するにはどうすればよいですか?
例
入力:
" aa aaa aaaa bb bbb bbbb cc ccc cccc cccc bbb bb aa "
出力:
List 1 = { aa, bb, cc} List 2 = { aaa, bbb, ccc} List 3 = { aaaa, bbbb, cccc}
Where
述語に一致する要素(この場合は正しい長さ)を見つけるために使用できます。
string[] words = input.Split();
List<string> twos = words.Where(s => s.Length == 2).ToList();
List<string> threes = words.Where(s => s.Length == 3).ToList();
List<string> fours = words.Where(s => s.Length == 4).ToList();
GroupBy
または、を使用してすべてのグループを一度に検索することもできます。
var groups = words.GroupBy(s => s.Length);
を使用ToLookup
して、特定の長さのすべての単語を簡単にインデックスに登録して検索することもできます。
var lookup = words.ToLookup(s => s.Length);
foreach (var word in lookup[3])
{
Console.WriteLine(word);
}
結果:
aaa bbb ccc
オンラインで動作することを確認してください:ideone
アップデートでは、空の文字列と重複した単語を削除したいようです。StringSplitOptions.RemoveEmptyEntries
前者はを使用して、後者はを使用して実行できますDistinct
。
var words = input.Split((char[])null, StringSplitOptions.RemoveEmptyEntries)
.Distinct();
var lookup = words.ToLookup(s => s.Length);
出力:
aa, bb, cc
aaa, bbb, ccc
aaaa, bbbb, cccc
オンラインで動作することを確認してください:ideone
編集:私の元の答えがOPが彼らの問題を解決するのを助けてくれてうれしいです。しかし、問題を少し考えた後、私はそれを適応させました(そして、私は投稿の最後に残した以前の解決策に反対することを強くお勧めします)。
string input = " aa aaa aaaa bb bbb bbbb cc ccc cccc cccc bbb bb aa ";
var words = input.Trim().Split().Distinct();
var lookup = words.ToLookup(word => word.Length);
まず、入力をトリミングして、外部スペースからの空の要素を回避します。次に、文字列を配列に分割します。単語の間に複数のスペースが含まれている場合は、 Markの回答のStringSplitOptions
ように使用する必要があります。
各単語を1回だけ含めるように呼び出した後、から にDistinct
変換します。ここで、単語の長さはキーで表され、単語自体は値に格納されます。words
IEnumerable<string>
Lookup<int, string>
(int)
(string)
ちょっと待ってください、それはどうして可能ですか?キーごとに複数の単語がありませんか?もちろんですが、それこそがLookup
クラスの目的です。
Lookup<TKey, TElement>
それぞれが1つ以上の値にマップされたキーのコレクションを表します。はにLookup<TKey, TElement>
似ていDictionary<TKey, TValue>
ます。違いは、ディクショナリがキーを単一の値にマップするのに対し、ルックアップはキーを値のコレクションにマップすることです。を実装するオブジェクトを
Lookup
呼び出すことにより、のインスタンスを作成できます。ToLookup
IEnumerable<T>
注
ルックアップの新しいインスタンスを作成するためのパブリックコンストラクターはありません。さらに、ルックアップオブジェクトは不変です。つまり、ルックアップの作成後に要素やキーを追加したり、ルックアップから削除したりすることはできません。
word => word.Length
KeySelectorラムダです。これはLookup
、単語の長さでインデックスを作成する(またはグループ化する)ことを定義します。
(質問の最初に要求された出力と同様)
foreach (var grouping in lookup)
{
Console.WriteLine("{0}: {1}", grouping.Key, string.Join(", ", grouping));
}
出力
2: aa, bb, cc 3: aaa, bbb, ccc 4: aaaa, bbbb, cccc
List
List<String> list3 = lookup[3].ToList();
(これらは返さIOrderedEnumerable<T>
れるため、キーによるアクセスはできなくなります)
var orderedAscending = lookup.OrderBy(grouping => grouping.Key);
var orderedDescending = lookup.OrderByDescending(grouping => grouping.Key);
元の答え-これを行わないでください(パフォーマンスの低下、コードの乱雑さ):
string input = " aa aaa aaaa bb bbb bbbb cc ccc cccc cccc bbb bb aa ";
Dictionary<int, string[]> results = new Dictionary<int, string[]>();
var grouped = input.Trim().Split().Distinct().GroupBy(s => s.Length)
.OrderBy(g => g.Key); // or: OrderByDescending(g => g.Key);
foreach (var grouping in grouped)
{
results.Add(grouping.Key, grouping.ToArray());
}
まず、単語のリストだけでなく長さも保持できるクラスを宣言しましょう
public class WordList
{
public int WordLength { get; set; }
public List<string> Words { get; set; }
}
これで、単語リストのリストを作成できます。
string input = " aa aaa aaaa bb bbb bbbb cc ccc cccc ";
string[] words = input.Trim().Split();
List<WordList> list = words
.GroupBy(w => w.Length)
.OrderBy(group => group.Key)
.Select(group => new WordList {
WordLength = group.Key,
Words = group.Distinct().OrderBy(s => s).ToList()
})
.ToList();
リストは、それぞれ長さおよび無意味にソートされています。
結果
例えば
list[2].WordLength ==> 4
list[2].Words[1] ==> "bbbb"
必要に応じて、結果をデータ構造に入れる代わりに、すぐに処理できます
string input = " aa aaa aaaa bb bbb bbbb cc ccc cccc ";
var query = input
.Trim()
.Split()
.GroupBy(w => w.Length)
.OrderBy(group => group.Key);
// Process the result here
foreach (var group in query) {
// group.Key ==> length of words
foreach (string word in group.Distinct().OrderBy(w => w)) {
...
}
}
LinqGroupByを使用できます
編集 ここで、Linqを適用して、出力に必要な文字列リストを生成しました。
edit2 は、編集された質問のように、複数の入力、単一の出力を適用しました。これは、Linqでの明確な呼び出しです。
string input = " aa aaa aaaa bb bbb bbbb cc ccc cccc ";
var list = input.Split(' ');
var grouped = list.GroupBy(s => s.Length);
foreach (var elem in grouped)
{
string header = "List " + elem.Key + ": ";
// var line = elem.Aggregate((workingSentence, next) => next + ", " + workingSentence);
// if you want single items, use this
var line = elem.Distinct().Aggregate((workingSentence, next) => next + ", " + workingSentence);
string full = header + " " + line;
Console.WriteLine(full);
}
// output: please note the last blank in the input string! this generates the 0 list
List 0: ,
List 2: cc, bb, aa
List 3: ccc, bbb, aaa
List 4: cccc, bbbb, aaaa
少し長い解決策ですが、辞書で結果を取得します
class Program
{
public static void Main()
{
Print();
Console.ReadKey();
}
private static void Print()
{
GetListOfWordsByLength();
foreach (var list in WordSortedDictionary)
{
list.Value.ForEach(i => { Console.Write(i + ","); });
Console.WriteLine();
}
}
private static void GetListOfWordsByLength()
{
string input = " aa aaa aaaa bb bbb bbbb cc ccc cccc ";
string[] inputSplitted = input.Split(' ');
inputSplitted.ToList().ForEach(AddToList);
}
static readonly SortedDictionary<int, List<string>> WordSortedDictionary = new SortedDictionary<int, List<string>>();
private static void AddToList(string s)
{
if (s.Length > 0)
{
if (WordSortedDictionary.ContainsKey(s.Length))
{
List<string> list = WordSortedDictionary[s.Length];
list.Add(s);
}
else
{
WordSortedDictionary.Add(s.Length, new List<string> {s});
}
}
}
}