Перебрать все варианты
От: koenjihyakkei Россия  
Дата: 18.12.18 14:16
Оценка:
Есть такой код (форов может быть гораздо больше):
    for (auto a : { 32, 64} )
    {
        for (auto b : { true, false} )
        {
            for (auto c : { 8, 16, 32, 64 } )
            {
            }
        }
    }

Хотелось бы поменять его примерно на такой:
    for (auto variant : Variants({ 32, 64}, { true, false}, { 8, 16, 32, 64 }) )
    {
    }

Можно ли как-нибудь такое провернуть?
Цель — избавиться от лесенки форов.
Отредактировано 18.12.2018 14:17 koenjihyakkei . Предыдущая версия .
Re: Перебрать все варианты
От: rg45 СССР  
Дата: 18.12.18 14:27
Оценка: 2 (1)
Здравствуйте, koenjihyakkei, Вы писали:

K>Есть такой код (форов может быть гораздо больше):

K> . . .
K>Можно ли как-нибудь такое провернуть?
K>Цель — избавиться от лесенки форов.

Вот здесь нашлось что-то похожее: https://codereview.stackexchange.com/questions/198475/generalized-cartesian-product.

С такой задачкой и самому было бы интересно поиграться. Забалабесить что-нибудь типа, cartesian_product, cortesian_iterator, cortesian_range... Имея вариадики, можно сделать просто конфетку.
--
Отредактировано 18.12.2018 20:53 rg45 . Предыдущая версия . Еще …
Отредактировано 18.12.2018 14:30 rg45 . Предыдущая версия .
Отредактировано 18.12.2018 14:28 rg45 . Предыдущая версия .
Re: Перебрать все варианты
От: sergii.p  
Дата: 18.12.18 15:23
Оценка: +7
Здравствуйте, koenjihyakkei, Вы писали:

а по моему, лесенка циклов читабельнее. Всё понятно — нужно буквально десять секунд, чтобы понять что происходит. Если же ввести что-то типа Variants, чужой человек зайдёт в файл variants.h и тут же застрелится.
Хотя конечно, если стоит задача поиграться с вариадиками...
Re: Перебрать все варианты
От: LaptevVV Россия  
Дата: 18.12.18 15:28
Оценка:
K>Цель — избавиться от лесенки форов.
Очень часто многократно вложенный цикл можно заменить двукратным вложенным.
Представь себе число из n "цифр"
Каждая "цифра" соответствует вложенному одному циклу.
Значение "цифры" — это количество повторений этого вложенного цикла.
Тогда внешний цикл — это перебор "цифр" числа. Либо от младшего "разряда" к старшему, либо наоборот.
А перебор значений каждой цифры от наименьшего до требуемого — это вложенный цикл.
Цифры числа, конечно могут быть в разных "системах счисления"
Надеюсь, понятно объяснил.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[2]: Перебрать все варианты
От: rg45 СССР  
Дата: 18.12.18 15:54
Оценка: +1
Здравствуйте, sergii.p, Вы писали:

SP>а по моему, лесенка циклов читабельнее. Всё понятно — нужно буквально десять секунд, чтобы понять что происходит. Если же ввести что-то типа Variants, чужой человек зайдёт в файл variants.h и тут же застрелится.


А это уже вопрос кривизны рук исполнителя. Ну зайдет он в "cartesian_product.hpp", увидит что то типа такого:

#pragma once

#include "cartesian_product_detail.hpp"

template <typename...Ranges>
cartesian_product<Ranges...> make_cartesian_product(Ranges&&...);


Ну и где-нибудь, в этом же файле, или отдельно, в документации, небольшой пример, как этим пользоваться:

for (const auto& entry : make_cartesian_product({ 32, 64}, { true, false}, { 8, 16, 32, 64 }))
{
  std::cout << "[" << entry.get<0>() << ", " << entry.get<1>() << ", " << entry.get<2>() << "]" << std::endl;
}


А при поддержке компилятором structured binding declarations намного красивее:

for (const auto& [key, value, description] : make_cartesian_product({ 32, 64}, { true, false}, { 8, 16, 32, 64 }))
{
  std::cout << "[" << key << ", " << value << ", " << description << "]" << std::endl;
}


А больше ему ничего видеть и не нужно. И где здесь повод, чтобы стреляться? Это только в кривых руках, и при путанице в голове, сложность реализации автоматически означает сложность в использовании. Настоящие профессионалы же тем и отличаются, что умеют сложные вещи сделать простыми.
--
Отредактировано 18.12.2018 18:16 rg45 . Предыдущая версия . Еще …
Отредактировано 18.12.2018 16:54 rg45 . Предыдущая версия .
Отредактировано 18.12.2018 16:34 rg45 . Предыдущая версия .
Отредактировано 18.12.2018 16:27 rg45 . Предыдущая версия .
Отредактировано 18.12.2018 16:26 rg45 . Предыдущая версия .
Отредактировано 18.12.2018 16:09 rg45 . Предыдущая версия .
Отредактировано 18.12.2018 16:09 rg45 . Предыдущая версия .
Отредактировано 18.12.2018 16:04 rg45 . Предыдущая версия .
Отредактировано 18.12.2018 16:03 rg45 . Предыдущая версия .
Отредактировано 18.12.2018 16:02 rg45 . Предыдущая версия .
Отредактировано 18.12.2018 16:01 rg45 . Предыдущая версия .
Отредактировано 18.12.2018 15:57 rg45 . Предыдущая версия .
Отредактировано 18.12.2018 15:54 rg45 . Предыдущая версия .
Re: Перебрать все варианты
От: Muxa  
Дата: 18.12.18 16:02
Оценка:
K>Можно ли как-нибудь такое провернуть?
K>Цель — избавиться от лесенки форов.

в google test есть реализация этого функционала
https://github.com/google/googletest/blob/master/googletest/include/gtest/gtest-param-test.h#L369
Re[2]: Перебрать все варианты
От: Mr.Delphist  
Дата: 18.12.18 16:40
Оценка: :)))
Здравствуйте, LaptevVV, Вы писали:

K>>Цель — избавиться от лесенки форов.

LVV>Очень часто многократно вложенный цикл можно заменить двукратным вложенным.
LVV>Представь себе число из n "цифр"
LVV>Каждая "цифра" соответствует вложенному одному циклу.
LVV>Значение "цифры" — это количество повторений этого вложенного цикла.
LVV>Тогда внешний цикл — это перебор "цифр" числа. Либо от младшего "разряда" к старшему, либо наоборот.
LVV>А перебор значений каждой цифры от наименьшего до требуемого — это вложенный цикл.
LVV>Цифры числа, конечно могут быть в разных "системах счисления"
LVV>Надеюсь, понятно объяснил.

Чорд, это самое короткое и понятное доказательство "P = NP" что я когда либо видел!
Re[3]: Перебрать все варианты
От: LaptevVV Россия  
Дата: 18.12.18 16:55
Оценка:
LVV>>Очень часто многократно вложенный цикл можно заменить двукратным вложенным.
LVV>>Представь себе число из n "цифр"
LVV>>Каждая "цифра" соответствует вложенному одному циклу.
LVV>>Значение "цифры" — это количество повторений этого вложенного цикла.
LVV>>Тогда внешний цикл — это перебор "цифр" числа. Либо от младшего "разряда" к старшему, либо наоборот.
LVV>>А перебор значений каждой цифры от наименьшего до требуемого — это вложенный цикл.
LVV>>Цифры числа, конечно могут быть в разных "системах счисления"
LVV>>Надеюсь, понятно объяснил.
MD>Чорд, это самое короткое и понятное доказательство "P = NP" что я когда либо видел!
Да при чем здесь доказательство-то?
Просто практика.
Ведь общее количество повторений не сокращается, просто код становится проще.
Ну, я подобный подход использовал при программировании числовых ребусов.
Но там все "цифры" в одной системе счисления, в 10-ной.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[2]: Перебрать все варианты
От: koenjihyakkei Россия  
Дата: 18.12.18 17:01
Оценка:
Здравствуйте, rg45, Вы писали:

R>Вот здесь нашлось что-то похожее: https://codereview.stackexchange.com/questions/198475/generalized-cartesian-product.


R>С такой задачкой и самому было бы интересно поиграться. Забалабесить что-нибудь типа, cortesian_product, cortesian_iterator, cortesian_range... Имея вариадики, можно сделать просто конфетку.


Спасибо! А то времени совсем нет даже погуглить
Re[2]: Перебрать все варианты
От: koenjihyakkei Россия  
Дата: 18.12.18 17:03
Оценка:
Здравствуйте, sergii.p, Вы писали:

Это используется в юнит тестах, где чужих не бывает Самая основная проблема в том, что идентация сильно съезжает вправо при большом количестве форов. В общем некрасиво и неудобно.
Re[2]: Перебрать все варианты
От: koenjihyakkei Россия  
Дата: 18.12.18 17:06
Оценка:
Здравствуйте, Muxa, Вы писали:

Эээх сначала так обрадовался, потому что код используется как раз в gtest. Но потом понял, что нужно писать отдельный Test fixture и вообще все сильно переделывать
Re[2]: Перебрать все варианты
От: koenjihyakkei Россия  
Дата: 18.12.18 17:08
Оценка: :)
Здравствуйте, LaptevVV, Вы писали:

K>>Цель — избавиться от лесенки форов.

LVV>Очень часто многократно вложенный цикл можно заменить двукратным вложенным.
LVV>Представь себе число из n "цифр"
LVV>Каждая "цифра" соответствует вложенному одному циклу.
LVV>Значение "цифры" — это количество повторений этого вложенного цикла.
LVV>Тогда внешний цикл — это перебор "цифр" числа. Либо от младшего "разряда" к старшему, либо наоборот.
LVV>А перебор значений каждой цифры от наименьшего до требуемого — это вложенный цикл.
LVV>Цифры числа, конечно могут быть в разных "системах счисления"
LVV>Надеюсь, понятно объяснил.

Если честно, немного(ничего) не понял.
Re: Перебрать все варианты
От: kov_serg Россия  
Дата: 18.12.18 17:21
Оценка: +1
Здравствуйте, koenjihyakkei, Вы писали:

K>Есть такой код (форов может быть гораздо больше):

K>
K>    for (auto a : { 32, 64} )
K>    {
K>        for (auto b : { true, false} )
K>        {
K>            for (auto c : { 8, 16, 32, 64 } )
K>            {
K>            }
K>        }
K>    }
K>

K>Хотелось бы поменять его примерно на такой:
K>
K>    for (auto variant : Variants({ 32, 64}, { true, false}, { 8, 16, 32, 64 }) )
K>    {
K>    }
K>

K>Можно ли как-нибудь такое провернуть?
K>Цель — избавиться от лесенки форов.
Что мешает использовать подпрограммы и лямбды:
  for_all_targets([](int arch,bool bedug,int color_len){
    ...
  });
Re: Перебрать все варианты
От: Voivoid Россия  
Дата: 18.12.18 17:49
Оценка: 19 (3)
Здравствуйте, koenjihyakkei, Вы писали:

K>Можно ли как-нибудь такое провернуть?

K>Цель — избавиться от лесенки форов.
Есть ж ranges-v3 ( который кстати в C++20 будет ) https://github.com/ericniebler/range-v3

Рабочий пример:
#include "range/v3/view/cartesian_product.hpp"
#include <iostream>

int main() {
  const auto as = {32, 64};
  const auto bs = {true, false};
  const auto cs = {8, 16, 32, 64};
  for (const auto v : ranges::view::cartesian_product(as, bs, cs)) {
    auto[a, b, c] = v;
    std::cout << a << " " << b << " " << c << '\n';
  }

  return 0;
}
Re[2]: Перебрать все варианты
От: rg45 СССР  
Дата: 18.12.18 18:09
Оценка: :))
Здравствуйте, Voivoid, Вы писали:

V>Есть ж ranges-v3 ( который кстати в C++20 будет ) https://github.com/ericniebler/range-v3

V>Рабочий пример:
V>
V>#include "range/v3/view/cartesian_product.hpp"
V> . . .
V>  for (const auto v : ranges::view::cartesian_product(as, bs, cs)) {
V>    auto[a, b, c] = v;
V>    std::cout << a << " " << b << " " << c << '\n';
V>  }
V>


Ну вот так всегда — а я-то думал, что это я придумал
Автор: rg45
Дата: 18.12.18
--
Отредактировано 18.12.2018 18:13 rg45 . Предыдущая версия . Еще …
Отредактировано 18.12.2018 18:10 rg45 . Предыдущая версия .
Re[3]: Перебрать все варианты
От: Alexander G Украина  
Дата: 18.12.18 18:20
Оценка:
Здравствуйте, koenjihyakkei, Вы писали:

K>Здравствуйте, sergii.p, Вы писали:


K>Это используется в юнит тестах, где чужих не бывает Самая основная проблема в том, что идентация сильно съезжает вправо при большом количестве форов. В общем некрасиво и неудобно.


Юнит тесты должны мыть максимально незамутнёнными и удобоотлаживаемыми.
Если проблема в идентации, я бы выносил внутренние функции, если проблема ещё и в дублировании этого набора циклов -- циклы вынести в метод, принимающий функтор.
Русский военный корабль идёт ко дну!
Re[4]: Перебрать все варианты
От: koenjihyakkei Россия  
Дата: 18.12.18 21:07
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Если проблема в идентации, я бы выносил внутренние функции, если проблема ещё и в дублировании этого набора циклов -- циклы вынести в метод, принимающий функтор.


Проблема именно в идентации, но в отдельную функцию выносить не хочется, потому что там не работают gtest'овские ассерты.
Re[2]: Перебрать все варианты
От: koenjihyakkei Россия  
Дата: 18.12.18 21:07
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Что мешает использовать подпрограммы и лямбды:

_>
_>  for_all_targets([](int arch,bool bedug,int color_len){
_>    ...
_>  });
_>


Немного не понял, что такое for_all_targets?
Re[5]: Перебрать все варианты
От: Alexander G Украина  
Дата: 19.12.18 05:00
Оценка:
Здравствуйте, koenjihyakkei, Вы писали:

K>Проблема именно в идентации, но в отдельную функцию выносить не хочется, потому что там не работают gtest'овские ассерты.


Дык, есть возможность Propagating Fatal Failures

Пример оттуда:

TEST(FooTest, Bar) {
  Subroutine();
  // Aborts if Subroutine() had a fatal failure.
  if (HasFatalFailure()) return;

  // The following won't be executed.
  ...
}


(Другая возможность — взять другой тестовый фреймворк, вроде Boost.Test, где fatal failures всегда сделаны не на return, а на исключениях)
Русский военный корабль идёт ко дну!
Отредактировано 19.12.2018 5:02 Alexander G . Предыдущая версия .
Re[2]: Перебрать все варианты
От: AleksandrN Россия  
Дата: 19.12.18 07:43
Оценка: +1
Здравствуйте, LaptevVV, Вы писали:

K>>Цель — избавиться от лесенки форов.

LVV>Очень часто многократно вложенный цикл можно заменить двукратным вложенным.
LVV>Представь себе число из n "цифр"
LVV>Каждая "цифра" соответствует вложенному одному циклу.
LVV>Значение "цифры" — это количество повторений этого вложенного цикла.
LVV>Тогда внешний цикл — это перебор "цифр" числа. Либо от младшего "разряда" к старшему, либо наоборот.
LVV>А перебор значений каждой цифры от наименьшего до требуемого — это вложенный цикл.
LVV>Цифры числа, конечно могут быть в разных "системах счисления"
LVV>Надеюсь, понятно объяснил.

В данном случае, думаю можно обойтись одним циклом.
for (auto a : { 32, 64} ) — перебирается 2 варианта, 0 — 32, 1 — 64
for (auto b : { true, false} ) — перебирается 2 варианта, 0 — false, 1 — true
for (auto c : { 8, 16, 32, 64 } ) — перебирается 4 варианта, т.е. хватит 2 бита — 00 — 8, 16 — 01, 32 — 10, 64 — 11

Засунем всё в один байт
00000000
    ^^^^
    ||||
    ||\+---- { 8, 16, 32, 64 }
    ||
    |\------ { true, false }
    |
    \------- { 32, 64}


Пройдём в цикле for ( int i = 0; i < 16; i++ ) и переберём все варианты, но по сравнению c тремя циклами, по коду будет неочевидно, зачем нужен этот цикл и к тому,же нужно будет интерпретировать такое представление в исходный вид для дальнейшей обработки. Т.е. — к этому коду потребуется подробный комментарий, который будет больше, чем код.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.