2

カスタム オブジェクトの 2 つのリストがあり、もう一方のリストに別のフィールドのペアに一致するオブジェクトがある場合、一方のリストのすべてのオブジェクトのフィールドを更新したいと考えています。

このコードは問題をよりよく説明し、私が望む結果を生成します。ただし、20k の大きなリスト、および一致するオブジェクトを含む 20k のリストの場合、これにはかなりの時間がかかります (31 秒)。ジェネリック リストの Find(Predicate) メソッドを使用すると、これを最大 50% 改善できます。

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;
namespace ExperimentFW3
{
    public class PropValue
    {
        public string Name;
        public decimal Val;
        public decimal Total;
    }
    public class Adjustment
    {
        public string PropName;
        public decimal AdjVal;
    }
    class Program
    {
        static List<PropValue> propList;
        static List<Adjustment> adjList;

        public static void Main()
        {
            propList = new List<PropValue>{
                new PropValue{Name = "Alfa", Val=2.1M},
                new PropValue{Name = "Beta", Val=1.0M},
                new PropValue{Name = "Gamma", Val=8.0M}
            };
            adjList = new List<Adjustment>{
                new Adjustment{PropName = "Alfa", AdjVal=-0.1M},
                new Adjustment{PropName = "Beta", AdjVal=3M}
            };

            foreach (var p in propList)
            {
                Adjustment a = adjList.SingleOrDefault(
                    av => av.PropName.Equals(p.Name)
                    );
                if (a != null)
                    p.Total = p.Val + a.AdjVal;
                else
                    p.Total = p.Val;
            }
        }
    }
}

望ましい結果は次のとおりです。アルファの合計 = 2、ベータの合計 = 4、ガンマの合計 = 8

しかし、これがさらに速くできるかどうかは疑問です。2 つのリストの内部結合は、結果セットで 20,000 個のアイテムをループする場合でも、ほとんど時間がかかりません。

var joined = from p in propList
             join a in adjList on p.Name equals a.PropName
             select new { p.Name, p.Val, p.Total, a.AdjVal };

私の質問は、T-SQL で行うようなことができるかどうかです。調整値で ISNULL(val,0) を使用した左結合からの UPDATE。

4

3 に答える 3

6

adjListこの結合は、最初にすべてをループしてルックアップを作成し、次にその中の各要素に対してルックアップを使用するため、かなり高速である必要がpropListあります。これは、大きなコードのO(N * M)メソッドよりも高速ですが、ループの前にonを呼び出すことでToLookup(またはToDictionary1つの値しか必要ないため)簡単に修正できます。adjList

編集:これは、を使用して変更されたコードToDictionaryです。テストされていません、気に留めてください...

var adjDictionary = adjList.ToDictionary(av => av.PropName);
foreach (var p in propList)
{
    Adjustment a;
    if (adjDictionary.TryGetValue(p.Name, out a))
    {
        p.Total = p.Val + a.AdjVal;
    }
    else
    {
        p.Total = p.Val;
    }
}
于 2008-11-07T09:47:30.927 に答える
0

これを投稿するのが遅れていることは知っていますが、adjList のルックアップごとに複数のレコードを処理する、以下のより明確で短い回答を誰かが高く評価すると思いました。ルックアップを作成すると、複数のアイテムの高速ルックアップが可能になり、ルックアップにレコードがない場合は空のリストが返されます。

var adjLookUp = adjList.ToLookUp(a => a.PropName);
foreach (var p in propList) 
    p.Total = p.Val + adjLookUp[p.Name].Sum(a => a.AdjVal);
于 2010-01-19T11:35:32.887 に答える
0

adjList の名前が重複している可能性がある場合は、ディクショナリにプッシュする前にアイテムをグループ化する必要があります。

Dictionary<string, decimal> adjDictionary = adjList
  .GroupBy(a => a.PropName)
  .ToDictionary(g => g.Key, g => g.Sum(a => a.AdjVal))

propList.ForEach(p => 
  {
    decimal a;
    adjDictionary.TryGetValue(p.Name, out a);
    p.Total = p.Val + a;
  });
于 2008-11-07T14:06:26.583 に答える