Подтвердить что ты не робот

Какой ваш любимый метод linq или "трюк"

Я знаю, что это очень субъективный вопрос (и тот, который может видеть шквал голосов "закрыть его" ), поэтому указывая его на CW и добавляя отказ от ответственности.

Во всяком случае, я работал над проектом в asp.net mvc, используя дозвуковой и внезапно (снова) пораженный элегантностью и "проницательностью" реализации linq, которая лежит на вершине как дозвукового, так и общего linq до библиотеки объектов. Это заставило меня немного приблизиться к моему коду и заставило меня понять, что некоторые из задач, которые я использовал linq для, будут бесконечно сложными (или "почти невозможными" - субъективными, конечно), если их попытают традиционным образом (это, конечно, вполне может быть ограничением во мне).

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

Чтобы начать, один сценарий, который я недавно использовал, имел объект, на котором было общее свойство "unitid". я хотел иметь возможность группировать набор из них, чтобы манипулировать и исследовать этот набор, когда он разбивается на соответствующие "унифицированные" группы. После долгих раздумий я подошел к этому простому маленькому линейному слою:

// the base collection of the objects - not grouped in any way
IQueryable<ShareholderRSP> rsps = validshareholderPounds
    .Where(x => x.Balance > 0)
    .OrderBy(x => x.RequestYear);

// the one-liner in question to group the objects by unitid
IList<IGrouping<string, ShareholderRSP>> groupedRSP =
     rsps.ToList().GroupBy(t => t.UnitID.ToString()).ToList();

который затем я мог использовать как:

foreach (var rspGrpItem in groupedRSP)
{
    foreach (var shareholderRSP in rspGrpItem)
    {
       // note, i could have also iterated this list too 
       // which is a base object contained within the collection
       // underneath the group collection item
    }
    // create a top level summary grouped by unitid
    // usedPounds is a variable created earlier on in the piece
    bookingConfirm.RSPUnitSelect.Add(
        new BookingConfirmRSPSelect
        {
            TotalBeforeUse = rspGrpItem.Sum(rsp => rsp.Balance),
            TotalAfterUse = rspGrpItem.Sum(rsp => rsp.Balance) - usedPounds,
            UnitNo = rspGrpItem.Key
        }
    );
}

Если бы я попытался сделать это традиционным способом, моя логика (на мой взгляд) была бы более громоздкой и менее способной адаптироваться к любым изменениям в базовой объектной модели.

Надеюсь, если это не совсем дискуссия, это подчеркнуло мою "радость" при использовании linq.

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

Глядя на некоторые прекрасные примеры.

джим

4b9b3361

Ответ 1

Простой трюк: быстрый способ генерации последовательности случайных чисел:

var randomNumbers = Enumerable.Repeat(new Random(), 10).Select(r => r.Next());

Ответ 2

Проект Euler проблема 8 - Найдите наибольший продукт из пяти последовательных цифр в 1000-значном номере. Я решил вчера использовать Linq и Lambda

        //orgStr - string variable holding 1000 digit number
        var max= Enumerable.Range(0, orgStr.Length - 5).Select(idx =>
        {
            return orgStr.Substring(idx, 5).Select(x => Int64.Parse(x.ToString()))
                .ToArray().Aggregate((a, b) => a * b);

        }).ToArray().Max();

Его довольно объяснительный я думаю

Ответ 3

Чтобы вычислить объединение коллекции прямоугольников:

var union = rects.Aggregate(Rectangle.Empty, Rectangle.Union);

Ответ 4

Часто вы просто используете оператор foreach или какой-то linq, но внутри него вам нужно дополнительно к самому элементу индекс. Для этого существует перегрузка select-statement.

var itemsWithIndex = myList.Select((item, index) => new { Item = item, Index = index });

foreach(var element in itemsWithIndex)
{
    Console.WriteLine("{0,-2} {1}", element.Index, element.Item.ToString());
}

Ответ 5

Прекрасная маленькая функция поворота найдена здесь: http://www.extensionmethod.net/Details.aspx?ID=147

public static Dictionary<TKey1, Dictionary<TKey2, TValue>> Pivot<TSource, TKey1, TKey2, TValue>
    (
        this IEnumerable<TSource> source, 
        Func<TSource, TKey1> key1Selector, 
        Func<TSource, TKey2> key2Selector,
        Func<IEnumerable<TSource>, TValue> aggregate
    )
{
    return source.GroupBy(key1Selector).Select(
    x => new
    {
        X = x.Key,
        Y = x.GroupBy(key2Selector).Select(
        z => new
        {
            Z = z.Key,
            V = aggregate(z)
        }
        ).ToDictionary(e => e.Z, o => o.V)
    }
    ).ToDictionary(e => e.X, o => o.Y);
}

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

var result = items.Pivot(s => s.SeasonID, 
                s => s.FundPropertyEntity.PropertyEntity.PropertyName, 
                lst => lst.Count());

ошеломляющая...

Ответ 6

Я слишком устал проверять нули:

var name = user.NoNull(x => x.Company)
  .NoNull(x => x.ParentCompany)
  .NoNull(x => x.Name, "N/A");

Я думаю, что метод расширения очевиден. Далее идет еще один метод расширения:

var total = user.NoNull(x => x.Company)
  .DefaultForNull(x => x.Users)
  .SelectMany(x => x.Email)
  .Where(x => x.EndsWith("@gmail.com"))
  .Count();

Теперь попробуйте сделать все это без такого метода расширения, предполагая, что любой объект в цепочке может быть NULL:)


Источник для тех, кто спрашивает:)

    public static TResult NoNull<TObject, TResult>(this TObject obj, Func<TObject, TResult> accessor, TResult defaultingTo = default(TResult)) {
        if (ReferenceEquals(obj, null))
            return defaultingTo;
        return accessor.Invoke(obj);
    }

    public static IEnumerable<TResult> DefaultForNull<TObject, TResult>(this TObject obj, Func<TObject, IEnumerable<TResult>> accessor, IEnumerable<TResult> defaultingTo = null) {
        if (ReferenceEquals(obj, null))
            return defaultingTo ?? Enumerable.Empty<TResult>();
        return accessor.Invoke(obj);
    }

Ответ 7

Это вспомогательный класс для построения строки запроса на основе коллекции параметров. Я поразился, как легко построить его в одном компактном выражении Linq. Когда я написал эту строку, я сразу же подключился к Linq!

 public class Parameters : System.Collections.Generic.Dictionary<string, object>
 {
   private string UrlEncode(object s)
   {
      return System.Web.HttpUtility.UrlEncode(s.ToString());
   }

   public override string ToString()
   {
      return string.Join("&", Keys.Select(k => string.Format("{0}={1}", k, UrlEncode(this[k]))));
   }
}

Ответ 8

отвечал на вопрос re Array.IndexOf() здесь на SO и "искажал" это вместе:):

.net мы бы "могли" сделать это обычно:

string[] testArray = { "cat", "dog", "banana", "orange" };
var indexOffset = Array.IndexOf(testArray, "banana");

"академическая" альтернатива в linq может быть:

string[] testArray = { "cat", "dog", "banana", "orange" };
var firstItem = testArray.Select((item, index) => new
{
    ItemName = item,
    Position = index

}).Where(i => i.ItemName == "banana")
  .First()
  .Position;

Не уверен, какие штрафы за производительность мы увидим здесь, но еще один способ обмануть кошку (или собаку или банан)

джим

Ответ 9

еще один новый источник получил и немного изменил. кивок в старый vb 'With' block:

public abstract class With
{
    public delegate void Operationdelegate<T>(T o);
    public static void Each<T>(
        IEnumerable<T> objects,
        Operationdelegate<T> f)
    {
        foreach (var i in objects) f(i);
    }
}

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

// in this case (get data - do action with the entity):
With.Each(
    _repository.Find(x => x.EmployeeID == 1),
        t => Console.WriteLine(t.OrderDate));

просто осознал силу этого сегодня после того, как он в моем классе хранилища ничего не делал за годы ":)

Ответ 10

было некоторое время, но вот небольшой метод расширения, который я собрал после повторения этого шаблона по крайней мере 3 раза в моем коде за последний день. В основном это берет исходный набор, группы в общем поле и возвращает значение MAX в этой группе, поэтому мы получаем подмножество max'd значение за ключ в исходной коллекции. Очевидно, что функция, выполняемая в совокупности, может быть любым действительным Func < > , который вам нравится (но это соответствует моей usecase):

public static class EnumerableUtils
{
    public static IEnumerable<T> GroupAndAggregate<T, T2>(
        this IEnumerable<T> source, 
        Func<T, T2> expressionGrp, 
        Func<T, T, T> expressionAggregate)
    {
        IEnumerable<T> ret = source.GroupBy(expressionGrp)
         .Select(g => g.Aggregate(expressionAggregate));

        return ret;
    }
}

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

// use a previously created enumerable object
var result = grpResult.GroupAndAggregate(
    g => g.FileLanguageCode, 
    (a, b) => (a.AddedDate > b.AddedDate) ? a : b);