Есть ли эффективный способ преобразовать набор в (список) целых чисел?

Я делаю некоторые операции над множествами, в результате чего получается набор, содержащий (для упрощения) одно целое число. Как я могу преобразовать набор обратно в uint? В настоящее время я делаю что-то вроде этого:

var my_set: set = [3];
var my_int: uint;
for i from 0 to MAX_UINT {
  if i in my_set { my_int = i; break };
};
print my_int; // should print "3"

Я использую Specman 13.1.

2 ответа

Я не знаком с какими-либо встроенными решениями, но вы можете использовать бинарный поиск, чтобы найти значение в O(log(n)) вместо O (n):

    var s: set = [1884667];

    var curr_min : uint = 0;
    var curr_max : uint = MAX_UINT;
    var pivot : uint;
    var curr_set : set;

    var done : bool = FALSE;

    while (!done) {     
        pivot = (curr_max + curr_min) / 2;

        curr_set = [curr_min..pivot];
        if (s in curr_set) {
            curr_max = pivot;
        } else {
            curr_min = pivot;
        };

        if (curr_min == curr_max || 
           curr_min + 1 == curr_max) {
            done = TRUE;
        };
    };    

    print curr_max;

Исходя из этого, довольно просто написать рекурсивную функцию, которая возвращает все значения в наборе для случаев, когда набор не является одиночным.

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

extend sys {
  run() is also {
    var my_1set : set = [1..5];
    var my_2set : set = [3..7, 10..13];
    var my_3set : set = [1..5,7..10,20..25];

    print convert_set(my_1set);
    print convert_set(my_2set);
    print convert_set(my_3set);
  };

  convert_set(my_set : set) : list of int is {
    var my_set_as_string :=  my_set.to_string();

    while TRUE {
      // split it using regexps - should always match
      assert str_match(my_set_as_string, "/(\d+\.\.\d+)(.*)/");

      result = { result;  generate_ints($1) };
      if $2 == "]" {
        break;
      };
      my_set_as_string = $2;
    };
  };

  generate_ints(interval : string) : list of int is {
    assert str_match(interval, "/(\d+)\.\.(\d+)/");
    for i from $1.as_a(int) to $2.as_a(int) {
      result = { result; i };
    };
  };
};

Это также не работает для всех целых чисел (только для целых чисел без знака) в его текущей форме, но это всего лишь вопрос настройки регулярных выражений. Вы можете проверить это и посмотреть, достаточно ли быстро. Если это так, мы / вы можете настроить регулярные выражения для работы с отрицательными целыми числами.

Другие вопросы по тегам