Вложенный цикл через 2 больших набора данных - PullRequest
0 голосов
/ 16 ноября 2011

У меня есть 2 набора данных из разных систем.Около 20000 записей за штуку.Один набор данных - List<Objects>, другой - RecordSet из системы, над которой я не имею никакого контроля (я могу только запрашивать записи и получать набор записей).

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

Существует ли быстрый способ получить совпадение и перейти к следующему объекту?

РЕДАКТИРОВАТЬ: СУЩЕСТВУЮЩИЙ КОД

Это очень простой вложенный цикл

results = _sr.SearchLst(ut.ToString(), searchSettings);

foreach (BL.Packet ePacket in eList) {

    for (Int32 j = 0; j < results.Rows.Length; j++) {

        String acckey = results.Rows[0].Data.GetValue(1).ToString();
        String taskname = results.Rows[0].Data.GetValue(2).ToString();

        if (acckey == ePacket.RecKey.ToString()) {
            ePacket.prop1 = taskname;
            ePacket.prop2 = acckey;
        }
    }
}

Я тоже смотрел на Линка, но не мог понять, как они будут вместе ... Я не уверен, что Линк все равно будет быстрее.

РЕШЕНИЕ:

Вот в основном то, что я в итоге сделал.

//move object from list to dictionary
var dict = eList.Cast<BaseObj>().ToDictionary(o => o.RecKey, o => o);

results = _sr.SearchLst(ut.ToString(), searchSettings);
if (results.Rows.Length > 0) {

    //loop through all rows in recordset
    for (Int32 j = 0; j < results.Rows.Length; j++) {
        id = Convert.ToInt32(results.Rows[j].Data.GetValue(1)); 
        taskname = results.Rows[j].Data.GetValue(2).ToString();

        if (dict.ContainsKey(id)) {
            //recordset id found in dictionary, so grab taskname
            ePacket = ((BL.Packet)dict[id]);
            ePacket.prop1 = taskname;
        }
    }
}

//move dictionary back to list
List<BaseObj> eListReturn = new List<BaseObj>(dict.Values);
return eListReturn;

Спасибо всем за помощь!

Ответы [ 4 ]

3 голосов
/ 16 ноября 2011

Попробуйте это:

var Object = from o in Objects
             join r in RecordSet equal o.YourKey equal r.YourForeignKey
             select Object { x = r.YourProperty };

Для дополнительной справки по LINQ здесь приведены 101 образец: http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b

(старое сообщение для справки)

Используйте LINQ, чтобы объединить две части, если информация в одном IEnumerable (например, в List). Что-то вроде

var combinedData = from i in listItems
                   join r in recordSet on r.ID equals i.ID
                   select new { i.Name, r.Property };

Вот ссылка на объединение с использованием LINQ http://www.dotnetperls.com/join Кроме того, примеры Google LINQ для вашей платформы .net есть много, и они довольно быстро делают именно то, что вы ищете.

Посмотрев SO на наличие похожих тем, я обнаружил кое-что весьма полезное, о чем я здесь кратко изложу. Проблема в том, что мы не уверены, что вы хотите сделать во внутренних скобках цикла.

Я предполагаю, что вам нужен только набор "виджетов", которые можно соединить со списком "гаджетов" по клавише.

Если вы хотите, чтобы группа виджетов и гаджетов была объединена в новый объект Whatsits - возможно, вы строите плоскую таблицу для диаграммы или что-то в этом роде, используйте этот пример:

var whatsits = from w in widgets
               join g in gadgets on w.gadgetID equal g.ID
               select new whatsit { name = w.name, id = w.ID };

Если вы хотите объединить несколько виджетов с гаджетами, где свойство гаджета = какое-то значение, а затем выполнить работу с каждым гаджетом, вы сначала собираете гаджеты, а затем выполняете поиск по новой коллекции, например:

var widgetList = from w in widgets
                 join g in gadgets on w.gadgetID equals g.ID
                 where g.Name = "whatsit"
                 select w;

foreach (widget w in widgetList)
{
    // Do a bunch of stuff to each widget
}

Обратите внимание, что может быть целесообразно выполнить тест производительности на приведенном выше LINQ, чтобы проверить, запускает ли он сначала лучший виджет или сначала гаджет в объединении.

2 голосов
/ 16 ноября 2011

Используйте Dictionary<TypeOfKey, SomeObject> в коллекции списков, которая у вас есть в памяти, заполните словарь, используя ключ в качестве ключа и объект в качестве значения.

Зацикливайте набор записей.Используя словарь, вы можете выполнить поиск (1) соответствующего элемента, чтобы исключить зацикливание в коллекции в памяти.

0 голосов
/ 16 ноября 2011

Если набор записей возвращает значения в отсортированном порядке, например,

значение ключа

'val' |1

'val2' |2

'val2' |3

'val2' |4

Тогда вы можете сделать соединение сортировки-слияния.вот псевдокод

while (!endofRecordset || !endofMyCollection) do
   if (recorset[rIndex].Key==myList[lIndex].Key)
       Join(recorset[rIndex], myList[lIndex])
   else if (recordset[rIndex] > myList[lIndex])
       lIndex++
   else 
       rIndex++
end while

РЕДАКТИРОВАТЬ:

здесь больше информации о объединение сортировки-слияния с примером в c #

0 голосов
/ 16 ноября 2011

Вы можете написать слой абстракции над объектами RecordSet и их API, которые позволяют получить доступ с помощью ключа.Это было бы как словарь от ключа к RecordSet.

У вас будет две итерации - по одной на каждую коллекцию.Две итерации - это O (N), тогда как вложенный цикл - это O (N ^ 2).

...