2015-03-16 2 views
3

Я пытаюсь создать подсчет количества раз, когда каждый ProductCode используется в моей базе данных. Проблема в том, что я не знаю, что все коды (или больше могут быть добавлены).Как найти индекс записи в TList?

Я предполагаю, что я мог бы использовать TList, с парами значений (ProductCode и количество), чтобы сделать это что-то вроде этого (я пытаюсь относиться к этому, как список <> из C# и т.д.)

procedure myProc 
type 
    TProductCodeCount = record 
    productCode : string; 
    count : integer; 
    end; 
var 
    productCodes : TList<TProductCodeCount>; 
    newProductCodeCount : TProductCodeCount; 
    currProductCodeCount : TProductCodeCount; 
    currentProductCode : string; 
    productCodeIndex : integer; 
begin 
    productCodes := TList<TProductCodeCount>.Create; 

    // Get my data set 
    // Loop through my data set 
    begin 
     currentProductCode := // value from the database ; 
     productCodeIndex := productCodes.indexOf(currentProductCode); 
     if productCodeIndex = -1 then 
     begin 
     newProductCodeCount.productCode := currentProductCode; 
     newProductCodeCount.count := 1; 

     productCodes.Add(newProductCodeCount) 
    end 
    else 
    begin 
     currProductCodeCount := productCodes.Extract(productCodeIndex); 
     currProductCodeCount.count := currProductCodeCount.count + 1' 
     productCodes.Delete(productCodeIndex); 
     productCodes.Add (currProductCodeCount); 
    end 
    end; 

    // Loop through my TList 
    begin 
    // do something with each productCode and count. 
    end 
end; 

Здесь есть две большие вещи.

  1. Я не уверен, как код сравнения для IndexOf работать (если это вообще возможно для TList рекордного типа
  2. Обновление элемента списка неуклюжее.

Как я могу сделать сравнение? Или есть гораздо лучший способ для достижения этой цели?

+0

Почему список пар ценностей? Если у вас XE7, вы можете использовать TDictionary . Затем сравнение можно выполнить, передав результат TComparer .Construct (... вот код кода ...) в словарь во время создания. –

+0

Я не очень хорошо разбираюсь в базах данных, но я бы ожидал, что что-то подобное можно сделать на уровне базы данных. Если поле productCode индексируется, то в базе данных уже есть все разные записи, хранящиеся в его индексной таблице. Как их получить, я не знаю. Также я уверен, что большинство баз данных позволяет вам получить количество записей, которые соответствуют конкретному запросу, без фактического их извлечения. Так что вам нужно всего лишь сделать определенный запрос для каждого конкретного productCode, чтобы узнать, сколько записей содержит этот конкретный код продукта. – SilverWarior

+5

Не могли бы вы просто запустить 'SELECT ProductCode, COUNT (ProductCode) FROM Products GROUP BY ProductCode'? –

ответ

4

вы можете использовать собственный компаратор, что вы пройдете к TList<T> во время строительства.

type 
    TProductCodeCountComparer = class(TComparer<TProductCodeCount>) 
    public 
    function Compare(const Left, Right: TProductCodeCount): Integer; override; 
    end; 

function TProductCodeCountComparer.Compare(const Left, Right: TProductCodeCount): Integer; 
begin 
    Result := CompareStr(Left.productCode, Right.productCode); 
end; 

var 
    Comparer: IComparer<TProductCodeCount> 

Comparer := TProductCodeCountComparer.Create; 
productCodes := TList<TProductCodeCount>.Create(Comparer); 

Вы также можете создать компаратор вместо

productCodes := TList<TProductCodeCount>.Create(
    TComparer<TProductCodeCount>.Construct(
    function (const Left, Right: TProductCodeCount): Integer 
     begin 
     Result := CompareStr(Left.productCode, Right.productCode); 
     end)); 

Для редактирования записей на месте можно использовать TList<T>.List свойства, которое дает вам прямой доступ к основным TList<T> массиву и позволяет непосредственно изменять записи в списке:

var 
    productCodes: TList<TProductCodeCount>; 
.... 
inc(productCodes.List[productCodeIndex].count); 

TList<T>.List property был представлен в XE3, для более ранних версий Delphi следующее расширение класса допускает внесение изменений в запись:

TXList<T> = class(TList<T>) 
    protected type 
    PT = ^T; 
    function GetPItem(index: Integer): PT; 
    public 
    property PItems[index: Integer]: PT read GetPItem; 
    end; 

function TXList<T>.GetPItem(index: Integer): PT; 
begin 
    Result := @FItems[index]; 
end; 

var 
    productCodes: TXList<TProductCodeCount>; 
.... 
inc(productCodes.PItems[productCodeIndex].count); 
+1

Вам лучше использовать 'Результат: = CompareStr (...); ' –

+1

Гораздо проще использовать' TComparer .Construct' и не нести накладные расходы на создание нового класса. –

+1

@ David Я предпочитаю классы, потому что они могут быть повторно использованы и протестированы более легко, а код более читабельен. –

Смежные вопросы