Come restituire il risultato booleano dai cicli di confronto per mantenere una migliore leggibilità?

1

Consideriamo che ho un'istanza std::string piena di dati testuali e un'istanza std::set<std::string> con parole chiave. Vorrei sapere se il testo memorizzato all'interno di std::string contiene tutte le parole chiave da std::set<std::string> . Per raggiungere questo obiettivo ho preso in considerazione due possibili implementazioni:

Restituzione di true o false esplicitamente

bool isContainsAllKeywords(const std::string& textualData,
                           const std::set<std::string>& keywords) {
    for(const auto& keyword : keywords) {
        if(textualData.find(keyword) == std::string::npos)
            return false;
    }
    return true;
}

Restituzione del risultato del confronto

bool isContainsAllKeywords(const std::string& textualData,
                           const std::set<std::string>& keywords) {
    auto keywordIterator = keywords.begin();
    for(; keywordIterator != keywords.end(); ++keywordIterator) {
        if(textualData.find(*keywordIterator) == std::string::npos)
            break;
    }
    return keywordIterator == keywords.end();
}

Dai miei esempi sopra quali sono più puliti e quale è il preferito? Poiché questa domanda può portare a risposte basate su opinioni, aggiungerei che mi aspetto risposte di riserva.

In ogni caso, forse entrambi i miei esempi sono sporchi, quindi in primo luogo vorrei sapere come risolvere questi problemi in modo pulito.

Modifica: la mia domanda mira alla leggibilità dei confronti basati su loop in cui un contenitore viene confrontato con un altro e generalmente non a: " Come faresti a sapere se hai scritto codice leggibile e facilmente gestibile? " .

    
posta Akira 25.11.2017 - 09:59
fonte

2 risposte

5

La nota nella risposta di Christophe è importante - il tuo approccio è forse inefficiente (specialmente per le lunghe stringhe di ricerca), e potrebbe non essere corretto (la parola chiave "if" appare se la stringa di ricerca contiene la parola "difficile"?) , il fatto che tu abbia un set suggerisce che sei supposto (supponendo che si tratti di un esercizio) per usare la sua funzionalità di ricerca. Ciò significa che probabilmente vorranno tokenizzare la stringa (dividerla in parole), quindi verificare la presenza di ciascuna parola nel gruppo di parole chiave.

Ignorando ciò, il modo migliore per scrivere questo codice è

bool contains(const std::string& haystack, const std::string& needle) {
  return haystack.find(needle) != std::string::npos;
}
bool containsAllKeywords(const std::string& haystack,
                         const std::set<std::string>& keywords)
{
  return std::all_of(keywords.begin(), keywords.end(),
   [&](const std::string& keyword) { return contains(haystack, keyword); });
}

La libreria standard ha molti algoritmi che danno nomi a costrutti di loop complessi. Questo rende il tuo codice molto più chiaro. (Cerca il principio "no raw loops" per maggiori informazioni.) Il triplo all_of , none_of e any_of è in grado di sostituire praticamente tutti i cicli con un ritorno booleano precoce.

Inoltre, per la leggibilità, consiglio sempre di eseguire funzioni di wrapper di piccole dimensioni per interazioni leggermente strane: la stringa non ti permette di chiedere "contiene un'altra stringa", invece devi scrivere s.find(t) != std::string::npos , o in parole, " è la posizione di un'altra stringa dentro di te non uguale a 'nessuna posizione' ".

Infine, forse vi trovate in una politica aziendale miope che dice che tutte le funzioni di ritorno booleano devono iniziare con "è", ma a meno che non lo siate, non scrivere mai una funzione con il nome "isContainsAllKeywords" o un altro nome che non si espande in una frase significativa.

    
risposta data 25.11.2017 - 13:30
fonte
1

Entrambe le varianti sono corrette.

Nel primo, il ritorno all'interno del ciclo mostra chiaramente che solo un errore è sufficiente per ottenere false e che si ottiene true solo se nessuna ricerca fallisce. Questo è molto auto esplicativo.

Nel secondo, quando vedi il ritorno, devi prima collegare la condizione al ciclo iteratore, quindi devi vedere quali condizioni ti fanno lasciare il ciclo prima. Non è difficile da capire, ma richiede una carica mentale più alta della prima.

Nota: fai scorrere più volte attraverso la stringa per cercare le diverse parole chiave. Hai considerato diversi approcci come iterare attraverso la stringa e contrassegnare le parole chiave o utilizzare un trie (non un albero!)?

    
risposta data 25.11.2017 - 13:09
fonte

Leggi altre domande sui tag