2013-11-27 31 views
6

我有一个列表。我想从类似元素的每次运行中获取最后一个值。如何从每个类似项目的运行中选择最后一个值?

我的意思是?让我举一个简单的例子。鉴于单词列表

[ '高尔夫球场', '时尚', '跳', '酒店', '草', '世界', '凌晨']

和相似的功能“开始用相同的字母,该函数将返回短名单

[ '高尔夫球场', '酒店', '草', '凌晨']

为什么?原始列表包含1个G字,1个H字,1个G字和2个W字。该函数返回每次运行的最后一个单词。

我该怎么做?


假设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

我希望看到'['hotel','grass','wee']'没有'高尔夫' –

回答

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

没什么用只是做了老式的方法太复杂:

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); 

你也可以把它变成一个通用的扩展方法为Tim Schmelter has done;我已经采取了几个步骤来有意概括代码(使用object作为键类型,使用IEnumerable<T>作为输入类型)。

0

试试这个algoritm

 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

因为你输入一个List <>,所以我认为这应该为你工作与可接受的性能,特别是它非常简洁:

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

你可以如果需要,可在结果上附加ToList()以获得List<string>

相关问题