11 Haziran 2020 Perşembe

std::transform metodu

Giriş
İmzası şöyle. Her sıralı hem de paralel türevleri var. Her türev için de UnaryOperation ve BinaryOperation alan alt türevler var.
template<class InputIterator, class OutputIterator, class UnaryOperation>
constexpr OutputIterator
transform(InputIterator first1, InputIterator last1, OutputIterator result,
  UnaryOperation op);

template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2,
 class UnaryOperation>
ForwardIterator2
transform(ExecutionPolicy&& exec, ForwardIterator1 first1, ForwardIterator1 last1,
 ForwardIterator2 result, UnaryOperation op);

template<class InputIterator1, class InputIterator2, class OutputIterator,
 class BinaryOperation>
constexpr OutputIterator
transform(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2,
 OutputIterator result, BinaryOperation binary_op);

template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2,
 class ForwardIterator, class BinaryOperation>
ForwardIterator
transform(ExecutionPolicy&& exec, ForwardIterator1 first1, ForwardIterator1 last1,
 ForwardIterator2 first2, ForwardIterator result, BinaryOperation binary_op);
1. Output Alanı
std::transform output için yer ayırmaz. Ya inplace işlem yaparız ya da output için kodla yer ayırırız ya da std::back_inserter kullanırız. Açıklaması şöyle.
std::transform doesn't extend a range, it only writes to on an existing one that's assumed non-empty. v1 is empty, so it cannot be made to store the result of the transformation. Your options are to either make sure v1 holds enough elements for the algorithm to overwrite:
transform metodu - Sequential UnaryOperation
std::transform UnaryOperation kendisine verilen iterator'ü değiştirmemelidir. Açıklaması şöyle
[alg.transform.1]
op [...] shall not invalidate iterators or subranges, or modify elements in the ranges
Şu kodların bazıları doğru bazıları yanlış.
auto unary_op = [](auto& value) 
{ 
  value = 10;    // this is bad
  return value;
}

auto unary_op = [&vec](auto const& value) 
{ 
  vec[0] = value;   // also bad
  return value;
}

auto unary_op = [&vec](auto& value) 
{ 
  vec.erase(vec.begin());   // nope 
  return value;
}
Şu kodların bazıları doğru bazıları yanlış.
auto unary_op = [](auto& value)  // const/ref not strictly needed
{         
  return value + 10;   // totally fine
}

auto unary_op = [&vec](auto& value)
{         
  return value + vec[0];   // ok in sequential but not in parallel execution
}
Örnek
Şöyle yaparız. Burada inplace işlem yapılıyor.
std::transform(vec.cbegin(),vec.cend(),vec.begin(),unary_op)
Örnek
Elimizde şöyle bir kod olsun.
vector<int> v{ 1,2,3,4,5 };
vector<int> v1;
Şu kod yanlıştır çünkü v1 için yer ayrılmamıştır.
std::transform(v.begin(), v.end(), v1.begin(), mult);
Düzeltmek için şöyle yaparız.
vector<int> v1(v.size());
Veya düzeltmek için şöyle yaparız.
std::transform(v.begin(), v.end(), std::back_inserter(v1), mult);
Örnek
Şöyle yaparız.
std::vector<std::size_t> ordinals;
std::transform(s.begin(), s.end(), std::back_inserter(ordinals),
               [](unsigned char c) -> std::size_t { return c; });
transform metodu - Sequential BinaryOperation 
Algoritmanın içi şöyle.
template<class InputIt1, class InputIt2, 
         class OutputIt, class BinaryOperation>
OutputIt transform(InputIt1 first1, InputIt1 last1, InputIt2 first2, 
                   OutputIt d_first, BinaryOperation binary_op)
{
    while (first1 != last1) {
        *d_first++ = binary_op(*first1++, *first2++);
    }
    return d_first;
}
Örnek
İki diziyi toplayıp, sonucu ilk diziye yazmak için şöyle yaparız.
std::transform(foo.begin(),foo.end(), bar.begin(), foo.begin(), std::plus<int>());
transform - Parallel
Örnek
Şöyle yaparız.
std::transform(std::execution::par_unseq, begin(u), end(u), begin(v), result,
  [](T & u, int v) { ...});

Hiç yorum yok:

Yorum Gönder