Как получить наибольшее значение из набора Delphi? - PullRequest
2 голосов
/ 07 мая 2009

Есть ли способ извлечь самое высокое (или самое низкое) значение в наборе? Например, если у меня есть следующий «набор байтов»:

[0, 1, 2, 4, 5, 28, 199]

есть ли какая-нибудь функция, которую я мог бы запустить и вернуть в результате 199?

РЕДАКТИРОВАТЬ: Существует очевидное решение грубой силы, включающее цикл for..in. Если возможно, я бы хотел найти лучший способ, чем этот.

Ответы [ 5 ]

14 голосов
/ 07 мая 2009

Цикл действительно формально правильный способ сделать это.

type
  TSetType = set of TEnumType;

function HighestMember(const s: TSetType): TEnumType;
begin
  for Result := High(Result) downto Low(Result) do
    if Result in s then
      exit;
  raise Exception.Create('empty sets have no highest member');
end;

Любое решение другого типа потребует приведения типов или ассемблера, которые вынуждают вас потерять безопасность типов - они, так сказать, выходят за пределы языка.

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

Если у вас нет 32-элементного ограничения на тип набора, значит, у вас есть ограничение Delphi в 256 элементов, и любое решение с битовым переворотом должно обрабатывать 32- байт .

6 голосов
/ 07 мая 2009

Наборы неупорядочены, поэтому вы не получите намного лучше, чем цикл. Если вы постоянно просматриваете минимальное / максимальное значение набора, тогда используйте структуру данных кучи , которая обеспечивает поиск O (1), чтобы получить минимальное / максимальное значение и поиск O (log n) на любое другое значение.

2 голосов
/ 07 мая 2009

Вот немного более быстрая версия, которая использует знание внутренней структуры набора байтов.

type
  TByteSet = set of Byte;

function HighestElement(const ByteSet: TByteSet): Byte;
type
  TSetBytes = array[0..SizeOf(TByteSet) - 1] of Byte;
var
  I, J: Integer;
  B: Byte;
  SetBytes: TSetBytes;
begin
  if ByteSet <> [] then
  begin
    SetBytes := TSetBytes(ByteSet);
    // Start at the top and work down, one byte at a time
    for I := SizeOf(TByteSet) - 1 downto 0 do
    begin
      // Any bits set here
      B := SetBytes[I];
      if B <> 0 then
      begin
        Result := I * 8;
        for J := 0 to 7 do
          if (B shr J) and 1 <> 0 then
          begin
            Result := Result + J;
            Exit;
          end;
      end;
    end;
  end else
    // No elements set
end;

Вы можете изменить тип набора TByteSet практически на любой тип набора, и эта функция все равно должна работать. Просто замените TByteSet в функции decl и body на тип вашего набора. Вы также можете изменить его так, чтобы он возвращал фактический тип элемента, если используется набор AnsiChar или набор некоторого типа перечисления. Чтобы получить наименьшее значение, измените цикл «I» для «0» на SizeOf (TByteSet) - 1 »и тест if в цикле« J »на« if (B shl J) и $ 80 <> 0 »

1 голос
/ 14 декабря 2017

Высшее и низшее, без использования математического блока:

type
  TCharSet = set of Char;

function MaxOfSet(aSet: TCharSet):Char;
var
  Data:array[0..SizeOf(TCharSet)-1] of Byte absolute aSet;
  i,r:Byte;
begin
  if aSet<>[] then begin
     i:=SizeOf(TCharSet)-1;
     while (i>0) and (Data[i]=0) do
        Dec(i);
     r:=i*8;
     i:=Data[i];
     while (i and $80)=0 do begin
        i:=i shl 1;
        Dec(r)
     end;
     Result:=Chr(r+7)
  end
  else
     raise Exception.Create('Unable to extract max value from an empty set');
end;

function MinOfSet(aSet: TCharSet):Char;
var
  Data:array[0..SizeOf(TCharSet)-1] of Byte absolute aSet;
  i,r:Byte;
begin
  if aSet<>[] then begin
     i:=0;
     while (i<SizeOf(TCharSet)-1) and (Data[i]=0) do
        Inc(i);
     r:=i*8;
     i:=Data[i];
     while (i and 1)=0 do begin
        i:=i shr 1;
        Inc(r)
     end;
     Result:=Chr(r)
  end
  else
     raise Exception.Create('Unable to extract min value from an empty set');
end;
1 голос
/ 04 ноября 2012

Почти то же самое, но короче:

type
  TByteSet = set of Byte;

function MaxSet(S: TByteSet): Byte;
var
  CardArr: Array [0..7] of Cardinal absolute S;
  i: Byte;
begin
  i := 7;
  while (i > 0) AND (CardArr[i] = 0) do
    Dec(i);
  Result := i + Floor(Log2(CardArr[i]));
end;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...