0

I am trying to solve the Question: Write a method to sort an array of strings so that all the anagrams are next to each other.

My approach for the problem is: Let's say vec is my vector of strings. I make map of 1st string, find it in the map. If it does not exist in the map, insert the string's map as key and that string as value (value field is a vector). If it exists in the map, add that string in the value field(which is a vector). Repeat for all the strings.

Data structure is like:

std::unordered_map<std::unordered_map<char,int>,std::vector<std::string>> map;
std::unordered_map<char, int> strMap;

for (auto each : vec)
{
    strMap = getMap(each);//getMap(string) will get the unordered_map of each string

    if (map.find(strMap) != map.end()) 
        map[strMap].push_back(each);
    else
        map.insert({ strMap, std::vector<std::string> {1,each} });
}

Can this be done? I am getting error: Error C2280 'std::hash<_Kty>::hash(const std::hash<_Kty> &)': attempting to reference a deleted function

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • 1
    Relevant: [Compilation error related to map and unordered_map: “attempting to reference a deleted function”](https://stackoverflow.com/questions/51220257/compilation-error-related-to-map-and-unordered-map-attempting-to-reference-a-d). It would be easier to use a hash whose keys are strings with letters sorted alphabetically, so `"bad"` and `"dab"` are both in the `"abd"` bucket. – Amadan Aug 08 '19 at 04:13
  • Are you looking for a good way to solve the problem (like using std:sort with a custom compare method) or information about nested maps? – Johnny Johansson Aug 08 '19 at 07:41
  • Can you provide an example of input data and expected output data? Somehow unclear to me. Please edit your question. – A M Aug 08 '19 at 09:47
  • `std::hash` is disabled for `unordered_map`, so it cannot be stored in an unordered associative like this. You have to provide your own hash function. – L. F. Aug 08 '19 at 13:37
  • Aside: You only need `map[getMap(each)].push_back(each);` because `[]` will construct an empty vector if necessary. – Caleth Aug 09 '19 at 12:28

1 Answers1

0

I am sorry that I do not answer your question regarding the map approach.

But because I think that other approaches maybe better, I will show you a different solution.

I will use the standard approach to find out, if a word is an anagram of another. The standard procedure is: Sort the letters in words. If 2 words with sorted letters are the same, then we have a anagram.

Very simple example:

gartner --> aegnrrt granter --> aegnrrt

So, what to do: We will make a copy of the original data. Additionally we store the index to the original data. Then, we sort the letters for all words in the copied list. And then, sort the list of words (with the sorted letters). As a result, the anagrams will be adjacent to each other.

In an additional loop, we will check the adjacent values and set a flag, if we found an anagram.

Then we show the result to the user.

Please see the attached code. Please note: It is one of many possibilities . . .

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <iomanip>
#include <iterator>
#include <iomanip>

// Random Word list
std::vector<std::string> words{"Lorem", "ipsum", "dolor", "sit", "amet", "consetetur", "sadipscing", "elitr", "sed", "diam", "nonumy", "eirmod", "tempor", "invidunt", "ut", "labore", "et", "dolore", "magna", "aliquyam", "erat", "sed", "diam", "voluptua", "At", "vero", "eos", "et", "accusam", "et", "justo", "duo", "dolores", "et", "ea", "rebum", "Stet", "clita", "kasd", "gubergren", "no", "sea", "takimata", "sanctus", "est", "Lorem", "ipsum", "dolor", "sit", "amet", "Lorem", "ipsum", "dolor", "sit", "amet", "consetetur", "sadipscing", "elitr", "sed", "diam", "nonumy", "eirmod", "tempor", "invidunt", "ut", "labore", "et", "dolore", "magna", "aliquyam", "erat", "sed", "diam", "voluptua", "At", "vero", "eos", "et", "accusam", "et", "justo", "duo", "dolores", "et", "ea", "rebum", "Stet", "clita", "kasd", "gubergren", "no", "sea", "takimata", "sanctus", "est", "Lorem", "ipsum", "dolor", "sit", "amet", "Lorem", "ipsum", "dolor", "sit", "amet", "consetetur", "sadipscing", "elitr", "sed", "diam", "nonumy", "eirmod", "tempor", "invidunt", "ut", "labore", "et", "dolore", "magna", "aliquyam", "erat", "sed", "diam", "voluptua", "At", "vero", "eos", "et", "accusam", "et", "justo", "duo", "dolores", "et", "ea", "rebum", "Stet", "clita", "kasd", "gubergren", "no", "sea", "takimata", "sanctus", "est", "Lorem", "ipsum", "dolor", "sit", "amet", "Duis", "autem", "vel", "eum", "iriure", "dolor", "in", "hendrerit", "in", "vulputate", "velit", "esse", "molestie", "consequat", "vel", "illum", "dolore", "eu", "feugiat", "nulla", "facilisis", "at", "vero", "eros", "et", "accumsan", "et", "iusto", "odio", "dignissim", "qui", "blandit", "praesent", "luptatum", "zzril", "delenit", "augue", "duis", "dolore", "te", "feugait", "nulla", "facilisi"};

// We want to copy the words into a list along with its index for sorting
struct WordWithIndex {
    WordWithIndex() {};
    WordWithIndex(const std::string&s, size_t i) : word(s), index(i) {};

    std::string word{};
    size_t index{};
    bool isAnagram{false};
};

int main()
{
    // Create a new vector and initialize the size
    std::vector<WordWithIndex> wordWithIndex(words.size());
    // COpy the word list into new vector
    std::transform(
        words.begin(), words.end(), wordWithIndex.begin(),
        [i=0U](const std::string& s) mutable { return WordWithIndex(s,i++);}
    );

    // Sort the letters in each word. Words with sorted letters, that are equal are an anagram
    std::for_each(wordWithIndex.begin(),wordWithIndex.end(),
        [](WordWithIndex& wwi) {std::sort(wwi.word.begin(),wwi.word.end());});

    // Now sort the word list with sort criteria : Words with sorted letters    
    std::sort( wordWithIndex.begin(), wordWithIndex.end(),
        [](WordWithIndex& wwi1, WordWithIndex& wwi2) {return wwi1.word < wwi2.word;}
    );

    // Find anagrams
    std::vector<WordWithIndex>::iterator wIter = wordWithIndex.begin();
    while (wIter != wordWithIndex.end()) {
        std::vector<WordWithIndex>::iterator adjacentFound = std::adjacent_find(
            wIter, wordWithIndex.end(),[](const WordWithIndex &a, const WordWithIndex &b){ return a.word == b.word;});
        if (adjacentFound !=  wordWithIndex.end()) {
            adjacentFound->isAnagram = true;
            ++adjacentFound;
            adjacentFound->isAnagram = true;
        }
        wIter = adjacentFound;
    }

    // Show result
    for (size_t i=0U; i < words.size(); ++i)
        std::cout << std::left << std::setw(4) << i << "\t" << std::setw(25) << words[wordWithIndex[i].index] << "\t\tIs Anagram:  " << std::boolalpha <<  wordWithIndex[i].isAnagram << "\n";

    return 0;
}
A M
  • 14,694
  • 5
  • 19
  • 44