2013-11-27 4 views
6

私はリストを持っています。私は、同様の要素の各実行から最後の値を取ってみたいと思います。類似のアイテムを実行するたびに最後の値を選択するにはどうすればよいですか?

どういう意味ですか?簡単な例を挙げましょう。

[ 'ゴルフ'、 ​​'ヒップ'、 'ホップ'、 'ホテル'、 '草'、 '世界'、 'おしっこ']

そして、類似度関数の単語のリストを考えます'同じ文字で始まる'、関数は短いリストを返します

[ 'ゴルフ'、 ​​'ホテル'、 '草'、 'おしっこ']

なぜ?元のリストは、G単語の1ラン、H単語の3ラン、Gワードの1ラン、およびWワードの2ランを有する。この関数は、各実行から最後の単語を返します。

どうすればいいですか?


仮定C#構文(実際に私は、顧客のオブジェクトで働いているが、私は自分自身を実行し、テストすることができ、何かを共有したいと思った)

> var words = new List<string>{"golf", "hip", "hop", "hotel", "grass", "world", "wee"}; 
> words.LastDistinct(x => x[0]) 
["golf", "hotel", "grass", "wee"] 

編集:私は.GroupBy(x => x[0]).Select(g => g.Last())を試してみましたが、その[grass]、 'hotel'、 'wee']はではなく、が欲しいものです。この例を注意深く読んでください。


編集。もう一つの例。

[ 'りんご'、 '軍隊'、 '黒'、 'ビール'、 '砦'、 '猫'、 'カート'、 'できる'、 '技術'、 '樹皮']

ここ5回のラン(Aさんのラン、Bさんの実行、Cさんの実行、Aさんのラン、Bさんの新しい実行)があります。各実行からの最後の言葉のようになります。

[「軍隊」、「要塞」、「カート」、「芸術」、「樹皮」]

理解する重要なことは、それぞれのことです実行は独立しています。開始時にAの実行と終了付近のAの実行を混在させないでください。

+0

と一緒に行きましたか? – dbw

+0

最初の文字だけでなく連続する単語でもグループ化したくないのですか? –

+0

私は ''ホテル '、'草 '、'ええ '' ''ゴルフなし 'を見ることを期待します –

答えて

0

私はあなたが必要とする特定の出力が何であるかを

/// <summary> 
/// Given a list, return the last value from each run of similar items. 
/// </summary> 
public static IEnumerable<T> WithoutDuplicates<T>(this IEnumerable<T> source, Func<T, T, bool> similar) 
{ 
    Contract.Requires(source != null); 
    Contract.Requires(similar != null); 
    Contract.Ensures(Contract.Result<IEnumerable<T>>().Count() <= source.Count(), "Result should be at most as long as original list"); 

    T last = default(T); 
    bool first = true; 
    foreach (var item in source) 
    { 
     if (!first && !similar(item, last)) 
      yield return last; 

     last = item; 
     first = false; 
    } 

    if (!first) 
     yield return last; 
} 
0

次の拡張方法を使用して、シーケンスをグループに分割することができます。いくつかの条件によってサブsequnces):

public static IEnumerable<IEnumerable<T>> Split<T, TKey>(
    this IEnumerable<T> source, Func<T, TKey> keySelector) 
{ 
    var group = new List<T>(); 

    using (var iterator = source.GetEnumerator()) 
    { 
     if (!iterator.MoveNext()) 
      yield break; 
     else 
     { 
      TKey currentKey = keySelector(iterator.Current); 
      var keyComparer = Comparer<TKey>.Default; 
      group.Add(iterator.Current); 

      while (iterator.MoveNext()) 
      { 
       var key = keySelector(iterator.Current); 
       if (keyComparer.Compare(currentKey, key) != 0) 
       { 
        yield return group; 
        currentKey = key; 
        group = new List<T>(); 
       } 

       group.Add(iterator.Current); 
      } 
     } 
    } 

    if (group.Any()) 
     yield return group;   
} 

そして、あなたの期待通りの結果を得ることは次のようになります。

string[] words = { "golf", "hip", "hop", "hotel", "grass", "world", "wee" }; 

var result = words.Split(w => w[0]) 
        .Select(g => g.Last()); 

結果:

golf 
hotel 
grass 
wee 
+0

これは誤字ではなく、私のコメントを読んでください。 –

1

あなたは、隣接することでグループ化することができ、この拡張機能を使用することができます/連続する要素:

public static IEnumerable<IGrouping<TKey, TSource>> GroupAdjacent<TSource, TKey>(
    this IEnumerable<TSource> source, 
    Func<TSource, TKey> keySelector) 
{ 
    TKey last = default(TKey); 
    bool haveLast = false; 
    List<TSource> list = new List<TSource>(); 
    foreach (TSource s in source) 
    { 
     TKey k = keySelector(s); 
     if (haveLast) 
     { 
      if (!k.Equals(last)) 
      { 
       yield return new GroupOfAdjacent<TSource, TKey>(list, last); 
       list = new List<TSource>(); 
       list.Add(s); 
       last = k; 
      } 
      else 
      { 
       list.Add(s); 
       last = k; 
      } 
     } 
     else 
     { 
      list.Add(s); 
      last = k; 
      haveLast = true; 
     } 
    } 
    if (haveLast) 
     yield return new GroupOfAdjacent<TSource, TKey>(list, last); 
} 

public class GroupOfAdjacent<TSource, TKey> : IEnumerable<TSource>, IGrouping<TKey, TSource> 
{ 
    public TKey Key { get; set; } 
    private List<TSource> GroupList { get; set; } 
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
    { 
     return ((System.Collections.Generic.IEnumerable<TSource>)this).GetEnumerator(); 
    } 
    System.Collections.Generic.IEnumerator<TSource> System.Collections.Generic.IEnumerable<TSource>.GetEnumerator() 
    { 
     foreach (var s in GroupList) 
      yield return s; 
    } 
    public GroupOfAdjacent(List<TSource> source, TKey key) 
    { 
     GroupList = source; 
     Key = key; 
    } 
} 

そして、それは簡単です:

var words = new List<string>{"golf", "hip", "hop", "hotel", "grass", "world", "wee"}; 
IEnumerable<string> lastWordOfConsecutiveFirstCharGroups = words 
      .GroupAdjacent(str => str[0]) 
      .Select(g => g.Last()); 

出力:

string.Join(",", lastWordOfConsecutiveFirstCharGroups); // golf,hotel,grass,wee 

あなたの他のサンプル:

words=new List<string>{"apples", "armies", "black", "beer", "bastion", "cat", "cart", "able", "art", "bark"}; 
lastWordOfConsecutiveFirstCharGroups = words 
    .GroupAdjacent(str => str[0]) 
    .Select(g => g.Last()); 

出力:

string.Join(",", lastWordOfConsecutiveFirstCharGroups); // armies,bastion,cart,art,bark 

Demonstration

1

ちょうどそれを昔ながらの方法やっと複雑すぎる何もありません:あなたはまた、Tim Schmelter has doneとして一般的な拡張メソッドにこれを回すことができる

Func<string, object> groupingFunction = s => s.Substring(0, 1); 
IEnumerable<string> input = new List<string>() {"golf", "hip", "..." }; 

var output = new List<string>(); 

if (!input.Any()) 
{ 
    return output; 
} 

var lastItem = input.First(); 
var lastKey = groupingFunction(lastItem); 
foreach (var currentItem in input.Skip(1)) 
{ 
    var currentKey = groupingFunction(str); 
    if (!currentKey.Equals(lastKey)) 
    { 
     output.Add(lastItem); 
    } 
    lastKey = currentKey; 
    lastItem = currentItem; 
} 

output.Add(lastItem); 

は、私はすでに目的コードを一般化するためにいくつかのステップを踏んでいます(objectをキータイプ、IEnumerable<T>を入力タイプとして使用しています)。

0

あなたの入力が一覧<>ですので、私は、これは許容できるパフォーマンスであなたのために働くべきだと思いますし、特に、それは非常に簡潔なので、このそのアルゴリズム

 var words = new List<string> { "golf", "hip", "hop", "hotel", "grass", "world", "wee" }; 
     var newList = new List<string>(); 
     int i = 0; 
     while (i < words.Count - 1 && i <= words.Count) 
     { 
      if (words[i][0] != words[i+1][0]) 
      { 
       newList.Add(words[i]); 
       i++; 
      } 
      else 
      { 
       var j = i; 
       while (j < words.Count - 1 && words[j][0] == words[j + 1][0]) 
       { 
        j++; 
       } 
       newList.Add(words[j]); 
       i = j+1; 
      } 
     } 
0

をお試しください:

var result = words.Where((x, i) => i == words.Count - 1 || 
            words[i][0] != words[i + 1][0]); 

することができます必要に応じてToList()を結果に加えてList<string>にします。

関連する問題