Created
April 9, 2011 07:49
-
-
Save ane/911220 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Geneerisiä C++-toteutuksia Haskellin (2-)tuplafunktioista, ks. | |
// http://hackage.haskell.org/packages/archive/base/4.1.0.0/doc/html/Prelude.html#19 | |
// uuden C++ 2011 -standardin ominaisuuksista osaa käyttäen. | |
// | |
// Kääntyy GCC 4.5.1 vivulla -std=c++0x | |
// ja VS2010 sellaisenaan. | |
// | |
// (c) ane 2011 <ane@iki.fi> (lisenssi: bsd v3) | |
#include <iostream> | |
#include <vector> | |
#include <iterator> | |
#include <algorithm> | |
#include <tuple> | |
#include <string> | |
#include <functional> | |
using namespace std; | |
// Transforms two lists (vectors) into a list of tuples | |
// e.g. zipping [1,2,3,4] with ['a', 'b', 'c', 'd'] would | |
// yield [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')]. | |
template <typename First, typename Second> | |
vector<tuple<First, Second>> zip(vector<First>& firstList, vector<Second>& secondList) | |
{ | |
vector<tuple<First, Second>> tupleVec; | |
auto firstIter = firstList.begin(); | |
auto secondIter = secondList.begin(); | |
// Assume the two lists are isomorphisms, so the resulting list | |
// spans the shortest one of the two. | |
while (firstIter != firstList.end() && secondIter != secondList.end()) | |
{ | |
auto newTuple = make_tuple(*firstIter, *secondIter); | |
tupleVec.emplace_back(newTuple); | |
firstIter++; | |
secondIter++; | |
} | |
return tupleVec; | |
} | |
// Transforms a list of tuples into two lists, where the first | |
// list is the list of the first values and the second list | |
// is the list of the second values, e.g., transforming | |
// [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')] | |
// into | |
// ([1,2,3,4], ['a', 'b', 'c', 'd']) | |
template <typename First, typename Second> | |
tuple<vector<First>, vector<Second>> unzip(vector<tuple<First, Second>>& zippedList) | |
{ | |
vector<First> firstList; | |
vector<Second> secondList; | |
for (auto iter = zippedList.begin(); iter != zippedList.end(); iter++) | |
{ | |
First fst = get<0>(*iter); | |
Second snd = get<1>(*iter); | |
firstList.emplace_back(fst); | |
secondList.emplace_back(snd); | |
} | |
return make_tuple(firstList, secondList); | |
} | |
// Combines two lists using a function that takes an input pair | |
// consisting of the items in the first list and the items in the second list, | |
// fusing the two lists together using a custom function. | |
// | |
// For example, if the function is simply a * b, and the first list would be | |
// [1, 3, 5, 7] and the second [2, 4, 6, 8], the resulting list would be | |
// [2, 12, 30, 42]. | |
// | |
// Keep in mind zip can be defined using this function, where func simply produces | |
// a tuple of the form (First, Second). | |
template <typename First, typename Second, typename Result> | |
vector<Result> zip_with(vector<First>& firstList, vector<Second>& secondList, const function<Result (First, Second)>& func) | |
{ | |
auto tuples = zip(firstList, secondList); | |
vector<Result> resultVec; | |
for (auto tupleIter = tuples.begin(); tupleIter != tuples.end(); tupleIter++) | |
{ | |
First fst = get<0>(*tupleIter); | |
Second snd = get<1>(*tupleIter); | |
// Apply the function on the tuple items | |
Result res = func(fst, snd); | |
resultVec.emplace_back(res); | |
} | |
return resultVec; | |
} | |
// Does the inverse of zip_with. Uses a function to parse an input value, e.g. "1:a", to generate | |
// two separate lists from tuples. For example, giving it a function that splits at ":" and produces a tuple | |
// (1, a). Thus ["1:a", "2:b", "3:c"] would turn into ([1,2,3], ["a", "b", "c"]). | |
template <typename First, typename Second, typename Input> | |
tuple<vector<First>, vector<Second>> unzip_with(vector<Input>& inputList, const function<tuple<First, Second> (Input)>& func) | |
{ | |
vector<tuple<First, Second>> tuples; | |
for (auto inputIter = inputList.begin(); inputIter != inputList.end(); inputIter++) | |
{ | |
tuple<First, Second> newTuple = func(*inputIter); | |
tuples.emplace_back(newTuple); | |
} | |
return unzip(tuples); | |
} | |
int main() | |
{ | |
typedef tuple<int, string> MyTuple; | |
vector<int> intVec; | |
vector<string> strVec; | |
for (int i = 0; i < 10; i++) { | |
intVec.emplace_back(i); | |
strVec.emplace_back(string(1, i + 'a')); | |
} | |
auto zipped = zip(intVec, strVec); | |
auto unzipped = unzip(zipped); | |
// Anonymous function for converting 1 and "a" into "1:a". | |
auto joinWithColonFunc = [&](const int& first, const string& second) { | |
// FYI: VS2010 bug: http://bit.ly/fCxvC5 | |
// To compile this on VS2010, cast first to long long. | |
return to_string(first) + ":" + second; | |
}; | |
// Splits a string into two from "x:y", reading x as an integer | |
// and y as a string. | |
auto splitterFunc = [&](const string& item) -> MyTuple { | |
int wheres_my_colon = item.find(":"); | |
string first = item.substr(0, wheres_my_colon); | |
string second = item.substr(wheres_my_colon + 1); | |
int firstVal = stoi(first); // string to integer | |
return make_tuple(firstVal, second); | |
}; | |
// (Why does this need an explicit template parameter list? | |
auto zipped_with = zip_with<int, string, string>(intVec, strVec, joinWithColonFunc); | |
vector<string> blargVec; blargVec.emplace_back("1:a"); blargVec.emplace_back("2:b"); blargVec.emplace_back("3:b"); | |
auto unzipped_with = unzip_with<int, string, string>(blargVec, splitterFunc); | |
// Mostly ugly printing stuff. | |
// Print the zipped list. | |
for_each(zipped.begin(), zipped.end(), [&](const MyTuple& tup) { | |
cout << "(" << get<0>(tup) << ", " << get<1>(tup) << ")" << endl; } | |
); | |
// Print the function zipped list. | |
cout << "["; copy(zipped_with.begin(), zipped_with.end(), ostream_iterator<string>(cout, ", ")); cout << "]" << endl; | |
// Print the unzipped list in a pretty format! | |
auto vecA = get<0>(unzipped); | |
auto vecB = get<1>(unzipped); | |
cout << "(["; | |
copy(vecA.begin(), vecA.end(), ostream_iterator<int>(cout, ", ")); | |
cout << "], ["; | |
copy(vecB.begin(), vecB.end(), ostream_iterator<string>(cout, ", ")); | |
cout << "])" << endl; | |
// Printing unzipped_with is omitted - it is the same as the above. | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment