Используйте Linq для нахождения последовательно повторяющихся элементов

Вот метод расширения в VB.NET для класса изображений

Imports System.Runtime.CompilerServices

Namespace Extensions
   ''' <summary>
   ''' Extensions for the Image class.
   ''' </summary>
   ''' <remarks>Several usefull extensions for the image class.</remarks>
   Public Module ImageExtensions

      ''' <summary>
      ''' Extends the image class so that it is easier to get a thumbnail from an image
      ''' </summary>
      ''' <param name="Input">Th image that is inputted, not really a parameter</param>
      ''' <param name="MaximumSize">The maximumsize the thumbnail must be if keepaspectratio is set to true then the highest number of width or height is used and the other is calculated accordingly. </param>
      ''' <param name="KeepAspectRatio">If set false width and height will be the same else the highest number of width or height is used and the other is calculated accordingly.</param>
      ''' <returns>A thumbnail as image.</returns>
      ''' <remarks>
      ''' <example>Can be used as such. 
      ''' <code>
      ''' Dim _NewImage as Image 
      ''' Dim _Graphics As Graphics
      ''' _Image = New Bitmap(100, 100)
      ''' _Graphics = Graphics.FromImage(_Image)
      ''' _Graphics.FillRectangle(Brushes.Blue, New Rectangle(0, 0, 100, 100))
      ''' _Graphics.DrawLine(Pens.Black, 10, 0, 10, 100)
      ''' Assert.IsNotNull(_Image)
      ''' _NewImage = _Image.ToThumbnail(10)
      ''' </code>
      ''' </example>
      ''' </remarks>
      <Extension()> _
      Public Function ToThumbnail(ByVal Input As Image, ByVal MaximumSize As Integer, Optional ByVal KeepAspectRatio As Boolean = True) As Image
         Dim ReturnImage As Image
         Dim _Callback As Image.GetThumbnailImageAbort = Nothing
         Dim _OriginalHeight As Double
         Dim _OriginalWidth As Double
         Dim _NewHeight As Double
         Dim _NewWidth As Double
         Dim _NormalImage As Image
         Dim _Graphics As Graphics

         _NormalImage = New Bitmap(Input.Width, Input.Height)
         _Graphics = Graphics.FromImage(_NormalImage)
         _Graphics.DrawImage(Input, 0, 0, Input.Width, Input.Height)
         _OriginalHeight = _NormalImage.Height
         _OriginalWidth = _NormalImage.Width
         If KeepAspectRatio = True Then
            If _OriginalHeight > _OriginalWidth Then
               If _OriginalHeight > MaximumSize Then
                  _NewHeight = MaximumSize
                  _NewWidth = _OriginalWidth / _OriginalHeight * MaximumSize
               Else
                  _NewHeight = _OriginalHeight
                  _NewWidth = _OriginalWidth
               End If
            Else
               If _OriginalWidth > MaximumSize Then
                  _NewWidth = MaximumSize
                  _NewHeight = _OriginalHeight / _OriginalWidth * MaximumSize
               Else
                  _NewHeight = _OriginalHeight
                  _NewWidth = _OriginalWidth
               End If
            End If
         Else
            _NewHeight = MaximumSize
            _NewWidth = MaximumSize
         End If
         ReturnImage = _
            _NormalImage.GetThumbnailImage(Convert.ToInt32(_NewWidth), Convert.ToInt32(_NewHeight), _Callback, _
                                    IntPtr.Zero)
         _NormalImage.Dispose()
         _NormalImage = Nothing
         _Graphics.Dispose()
         _Graphics = Nothing
         _Callback = Nothing
         Return ReturnImage
      End Function
   End Module
End Namespace

Извините, кодовый тег не любит код vb.net.

7
задан Jürgen Steinblock 10 January 2018 в 07:16
поделиться

7 ответов

Там не будет ничего встроенного в эти строки, но если вам это нужно часто, вы можете сделать что-нибудь индивидуальное, но довольно общее:

static IEnumerable<TSource> WhereRepeated<TSource>(
    this IEnumerable<TSource> source)
{
    return WhereRepeated<TSource,TSource>(source, x => x);
}
static IEnumerable<TSource> WhereRepeated<TSource, TValue>(
    this IEnumerable<TSource> source, Func<TSource, TValue> selector)
{
    using (var iter = source.GetEnumerator())
    {
        if (iter.MoveNext())
        {
            var comparer = EqualityComparer<TValue>.Default;
            TValue lastValue = selector(iter.Current);
            while (iter.MoveNext())
            {
                TValue currentValue = selector(iter.Current);
                if (comparer.Equals(lastValue, currentValue))
                {
                    yield return iter.Current;
                }
                lastValue = currentValue;
            }
        }
    }
}

Использование:

    foreach (Value value in values.WhereRepeated(x => x.Name))
    {
        Console.WriteLine(value.Name);
    }

Вы можете подумать о том, что делать с тройками и т. д. - в настоящее время будет выдано все, кроме первого (что соответствует вашему описанию), но это может быть не совсем правильно.

7
ответ дан 6 December 2019 в 21:18
поделиться

Вы можете реализовать расширение Zip , затем заархивировать свой список с помощью .Skip (1), а затем выбрать строки, которые соответствуют.

Это должно работать и быть довольно простым в обслуживании:

values
  .Skip(1)
  .Zip(items, (first,second) => first.Name==second.Name?first:null)
  .Where(i => i != null);

Небольшой недостаток этого метода в том, что вы дважды просматриваете список.

4
ответ дан 6 December 2019 в 21:18
поделиться

Я думаю, это сработает (непроверено) - это даст вам и повторяющееся слово, и его индекс. Для множественных повторов вы можете просмотреть этот список и проверить последовательные индексы.

 var query = values.Where( (v,i) => values.Count > i+1 && v == values[i+1] )
                   .Select( (v,i) => new { Value = v, Index = i } );
1
ответ дан 6 December 2019 в 21:18
поделиться

Вот еще один простой подход это должно работать, если идентификаторы всегда последовательны, как в вашем примере:

var data = from v2 in values
            join v1 in values on v2.Id equals v1.Id + 1
            where v1.Name == v2.Name
            select v2;
1
ответ дан 6 December 2019 в 21:18
поделиться

Для этого можно использовать расширение GroupBy.

-1
ответ дан 6 December 2019 в 21:18
поделиться

Что-то вроде этого

var dupsNames = 
  from v in values
  group v by v.Name into g
  where g.Count > 1 // If a group has only one element, just ignore it
  select g.Key;

должно работать. Затем вы можете использовать результаты во втором запросе:

dupsNames.Select( d => values.Where( v => v.Name == d ) )

Это должно вернуть группировку с ключом = имя, значения = {элементы с именем}

Заявление об ограничении ответственности: я не тестировал вышеупомянутое, поэтому, возможно, я ошибаюсь.

-1
ответ дан 6 December 2019 в 21:18
поделиться

Я знаю, что это древний вопрос, но я просто работал над тем же, так что ....

static class utils
{
    public static IEnumerable<T> FindConsecutive<T>(this IEnumerable<T> data, Func<T,T,bool> comparison)
    {
        return Enumerable.Range(0, data.Count() - 1)
        .Select( i => new { a=data.ElementAt(i), b=data.ElementAt(i+1)})
        .Where(n => comparison(n.a, n.b)).Select(n => n.a);
    }
}

Должно сработать для чего угодно - просто предоставьте функцию для сравнения элементов

1
ответ дан 6 December 2019 в 21:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: