Skip to content

Instantly share code, notes, and snippets.

@dodheim
Last active August 27, 2017 18:00
Show Gist options
  • Save dodheim/3433f542c9d15c10ce2871bac3216bb9 to your computer and use it in GitHub Desktop.
Save dodheim/3433f542c9d15c10ce2871bac3216bb9 to your computer and use it in GitHub Desktop.
C++17 solution for /r/dailyprogrammer challenge #284 [easy]
#include <cstddef>
#include <cstdlib>
#include <utility>
#include <exception>
#include <stdexcept>
#include <chrono>
#include <string_view>
#include <string>
#include <unordered_map>
#include <vector>
#include <fstream>
#include <iostream>
#include <range/v3/core.hpp>
#include <range/v3/algorithm/for_each.hpp>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/transform.hpp>
#include <boost/functional/hash.hpp>
namespace rngs = ranges;
namespace rngvs = ranges::view;
using namespace std::string_view_literals;
using word_key = std::pair<char, char>;
constexpr word_key word_to_key(std::string_view const sv) noexcept { return {sv.front(), sv.back()}; }
using dictionary = std::unordered_map<word_key, std::vector<std::string>, boost::hash<word_key>>;
dictionary load_dictionary(char const* const path) {
static auto constexpr letters = "abcdefghijklmnopqrstuvwxyz"sv;
dictionary ret(letters.size() * letters.size());
for (auto const fl : letters) {
for (auto const ll : letters) {
ret[{fl, ll}];
}
}
if (std::ifstream words{path}) {
rngs::for_each(
rngs::getlines(words)
| rngvs::filter([](auto const& word) noexcept { return word.size() >= 5; }),
[&ret](auto const& word) { ret.find(word_to_key(word))->second.push_back(word); }
);
} else {
throw std::runtime_error{"path not found"};
}
return ret;
}
struct word_filter {
explicit constexpr word_filter(std::string_view const input) noexcept : input_{input} { }
constexpr bool operator ()(std::string_view const word) const noexcept {
auto input = input_;
for (auto const letter : word) {
if (auto const idx = input.find(letter); idx != input.npos) {
input.remove_prefix(idx);
} else {
return false;
}
}
return true;
}
private:
std::string_view input_;
};
static void impl(char const* const dictionary_path) {
namespace chrono = std::chrono;
auto const inputs = rngs::getlines(std::cin) | rngs::to_vector;
auto const start_time = chrono::high_resolution_clock::now();
auto const dict = load_dictionary(dictionary_path);
auto const loaded_time = chrono::high_resolution_clock::now();
auto const results =
inputs
| rngvs::transform([&dict](std::string_view const input) {
return std::make_pair(
input,
rngs::to_vector(
dict.find(word_to_key(input))->second
| rngvs::transform([](auto const& word) noexcept -> std::string_view { return word; })
| rngvs::filter(word_filter{input})
)
);
})
| rngs::to_vector;
auto const end_time = chrono::high_resolution_clock::now();
for (auto const& [input, words] : results) {
std::cout << input << '\n';
for (auto const word : words) {
std::cout << '\t' << word << '\n';
}
}
auto constexpr to_us = [](auto const dur) noexcept { return chrono::duration_cast<chrono::microseconds>(dur).count(); };
std::cout
<< "total time elapsed: "sv
<< to_us(end_time - start_time) << " us ("sv
<< to_us(loaded_time - start_time) << " us loading dictionary, "sv
<< to_us(end_time - loaded_time) << " us processing inputs)\n"sv;
}
int main(int argc, char* argv[]) {
if (argc == 2) {
std::ios::sync_with_stdio(false);
std::cerr << std::boolalpha;
std::cout << std::boolalpha;
try {
impl(argv[1]);
return EXIT_SUCCESS;
} catch (std::exception const& ex) {
std::cerr << ex.what() << '\n';
} catch (...) {
std::cerr << "unknown exception (...)\n"sv;
}
}
return EXIT_FAILURE;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment