Com o novo loop for baseado em intervalo, podemos escrever código como
for(auto x: Y) {}
Qual IMO é uma grande melhoria de (por exemplo)
for(std::vector<int>::iterator x=Y.begin(); x!=Y.end(); ++x) {}
Pode ser usado para fazer um loop em dois loops simultâneos, como a zip
função Pythons ? Para quem não está familiarizado com Python, o código:
Y1 = [1,2,3]
Y2 = [4,5,6,7]
for x1,x2 in zip(Y1,Y2):
print x1,x2
Dá como saída (1,4) (2,5) (3,6)
for
só pode ser usado com uma variável, portanto, não. Se você quisesse acessar dois valores ao mesmo tempo, teria que usar algo comostd::pair
zip()
função que retorne tuplas e itere sobre a lista de tuplas.for(;;)
pode obter esse comportamento, embora longo, então é realmente a questão: É possível para "auto" sobre dois objetos ao mesmo tempo?Respostas:
Aviso:
boost::zip_iterator
e aboost::combine
partir do Boost 1.63.0 (26 de dezembro de 2016) causará um comportamento indefinido se o comprimento dos contêineres de entrada não for o mesmo (pode falhar ou iterar além do final).A partir do Boost 1.56.0 (7 de agosto de 2014), você pode usar
boost::combine
(a função existe em versões anteriores, mas não documentada):Isso iria imprimir
Em versões anteriores, você mesmo poderia definir um intervalo desta forma:
O uso é o mesmo.
fonte
optional
elementos de possibilidades de iteração além do fim ...Então eu escrevi este zip antes, quando estava entediado, decidi postar porque é diferente dos outros porque não usa boost e se parece mais com c ++ stdlib.
Exemplo de uso:
fonte
[](int i,int j,float k,float l)
funciona? Esta é uma função lambda?std::for_each
mas você pode usar um número arbitrário de intervalos, os parâmetros no lambda dependem de quantos iteradores você atribui à funçãoVocê pode usar uma solução baseada em
boost::zip_iterator
. Faça uma classe de contêiner falsa mantendo referências a seus contêineres e que retornezip_iterator
das funções de membrobegin
eend
. Agora você pode escreverImplementação de exemplo (teste):
Deixo a versão variada como um excelente exercício para o leitor.
fonte
boost::iterator_range
+boost::zip_iterator
, até mesmo a versão variável.boost::zip_iterator
não funciona com intervalos de comprimentos diferentesstd :: transform pode fazer isso trivialmente:
Se a segunda sequência for mais curta, minha implementação parece estar fornecendo valores inicializados padrão.
fonte
b
.Consulte Recursos
<redi/zip.h>
para obter umazip
função que funciona com base de intervalofor
e aceita qualquer número de intervalos, que podem ser rvalues ou lvalues e podem ter comprimentos diferentes (a iteração irá parar no final do intervalo mais curto).Impressões
0 1 2 3 4 5
fonte
boost/tuple/tuple_io.hpp
paracout << i;
boost::get<0>(i)
eboost::get<1>(i)
. Não sei por que o exemplo original não pôde ser adaptado diretamente; pode ter a ver com o fato de que meu código faz referências constantes a contêineres.Com range-v3 :
A saída:
fonte
Encontrei esta mesma pergunta de forma independente e não gostei da sintaxe de nenhuma das opções acima. Portanto, tenho um arquivo de cabeçalho curto que basicamente faz o mesmo que zip_iterator boost, mas tem algumas macros para tornar a sintaxe mais palatável para mim:
https://github.com/cshelton/zipfor
Por exemplo, você pode fazer
O principal açúcar sintático é que posso nomear os elementos de cada recipiente. Eu também incluo um "mapfor" que faz o mesmo, mas para mapas (para nomear o ".first" e ".second" do elemento).
fonte
fonte
Se você gosta de sobrecarga do operador, aqui estão três possibilidades. Os dois primeiros estão usando
std::pair<>
estd::tuple<>
, respectivamente, como iteradores; o terceiro estende isso para baseado em alcancefor
. Observe que nem todo mundo vai gostar dessas definições de operadores, então é melhor mantê-los em um namespace separado e ter umusing namespace
nas funções (não arquivos!) Onde você gostaria de usá-los.fonte
Para uma biblioteca de processamento de fluxo C ++ que estou escrevendo, procuro uma solução que não dependa de bibliotecas de terceiros e funcione com um número arbitrário de contêineres. Acabei com esta solução. É semelhante à solução aceita que usa boost (e também resulta em comportamento indefinido se os comprimentos do contêiner não forem iguais)
fonte
operator*
forseq::iterator
retorna umastd::tuple
das referências const.Se você tiver um compilador compatível com C ++ 14 (por exemplo, gcc5), você pode usar
zip
acppitertools
biblioteca fornecida por Ryan Haining, que parece realmente promissora:fonte
Boost.Iterators tem
zip_iterator
você pode usar (exemplos nos documentos). Não funcionará com range for, mas você pode usarstd::for_each
e um lambda.fonte
for_each
seria menos incômodo.std::for_each(make_zip_iterator(make_tuple(Y1.begin(), Y2.begin())), make_zip_iterator(make_tuple(Y1.end(), Y2.end())), [](const tuple<int, int>& t){printf("%d %d\n", get<0>(t), get<1>(t)); });
:?Aqui está uma versão simples que não requer reforço. Não será particularmente eficiente, pois cria valores temporários e não generaliza sobre contêineres que não sejam listas, mas não tem dependências e resolve o caso mais comum de compactação.
Embora as outras versões sejam mais flexíveis, geralmente o objetivo de usar um operador de lista é criar uma linha simples. Esta versão tem a vantagem de que o caso comum é simples.
fonte