mikrocontroller.net

Forum: PC-Programmierung 2D array if statement


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Ich habe folgendes Array definiert:
char compare[5][2]={
  {'a', '1'},
  {'e', '2'},
  {'i', '3'},
  {'o', '4'},
  {'u', '5'}
}

ich möchte nun die Variabel x überprüfen of sie a,e,i,o oder u beträgt, 
und den entsprechenden in der 2. Spalte im array Wert zuweisen.

momentan habe ich es so gelöst:
for (int i=0; i<5; i++)
{
  if (x== compare[i][0])
  {
      x = compare[i][1];
  }
}


geht dies auch einfacher zu lösen ohne jedesmal mit einer for Schleife 
das ganze array zu durchforsten?

Autor: leo (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Peter schrieb:
> geht dies auch einfacher zu lösen ohne jedesmal mit einer for Schleife
> das ganze array zu durchforsten?

$ man bsearch

leo

Autor: A. S. (achs)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn der erste wert beliebig angeordnet ist, dann nicht.

Sonst ja.

Und alles kann man für Speed oder size optimieren.

Beitrag #5960159 wurde vom Autor gelöscht.
Autor: Niklas G. (erlkoenig) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Klasse std::map ist genau dafür gemacht:
#include <map>
#include <iostream>

int main () {
  std::map<char, char> compare {  {'a', '1'},
                  {'e', '2'},
                  {'i', '3'},
                  {'o', '4'},
                  {'u', '5'}};
  
  int x = 'e';
  auto iter = compare.find (x);
  if (iter != compare.end ()) {
    x = iter->second;
  }
  
  std::cout << static_cast<char>(x) << std::endl;
}

sie enthält eine Menge an Schlüssel-Wert-Zuweisungen. Man kann prüfen ob 
ein Wert enthalten ist und den abgebildeten Wert abfragen. Das 
Abfragen/Prüfen hat eine logarithmische Laufzeit, und ist damit 
schneller als die lineare Suche im Ausgangspost. Bei nur 5 Einträgen ist 
aber vermutlich der Overhead noch zu groß als dass das sinnvoll wäre.
Es gibt auch noch std::unordered_map mit durchschnittlich konstanter 
Laufzeit.

https://en.cppreference.com/w/cpp/container/map
https://en.cppreference.com/w/cpp/container/unordered_map

Autor: Dirk B. (dirkb2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter schrieb:
> geht dies auch einfacher zu lösen ohne jedesmal mit einer for Schleife
> das ganze array zu durchforsten?

du kannst bei einem Match (die Bedingung vom if ist wahr) die Schleife 
abbrechen.

Autor: KeinMathematiker (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Niklas G. schrieb:
> Die Klasse std::map ist genau dafür gemacht:#include <map>
> #include <iostream>
>
> int main () {
>   std::map<char, char> compare {  {'a', '1'},
>                   {'e', '2'},
>                   {'i', '3'},
>                   {'o', '4'},
>                   {'u', '5'}};
>
>   int x = 'e';
>   auto iter = compare.find (x);
>   if (iter != compare.end ()) {
>     x = iter->second;
>   }
>
>   std::cout << static_cast<char>(x) << std::endl;
> }


Bekommt man sowas auch auf einem uC zum laufen oder ist die Lib nur für 
x86?

Autor: Niklas G. (erlkoenig) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
KeinMathematiker schrieb:
> Bekommt man sowas auch auf einem uC zum laufen oder ist die Lib nur für
> x86?

Die C++ Standard Library ist an sich portabel, aber z.B. der AVR-G++ 
liefert sie nicht mit. Die dynamischen Standard-Container wie std::map 
sind vom Speicherverbrauch her aber nicht so für Mikrocontroller 
geeignet. Es war aber auch gar nicht nach uC gefragt, und das hier ist 
das PC-Programmieren-Forum...

Wenn es aber wirklich nur 5 Bytes sind ist die lineare Suche, oder 
einfach 5 Vergleiche, oder ein switch-case vermutlich schneller. Dank 
Cache ist der Arrayzugriff viel schneller als eine Baumstruktur in 
std::map.

Vielleicht lässt sich auch eine lustige bitweise Berechnung machen, die 
die 5 Vergleiche auf einmal macht. Die 5 Werte zu einem 64bit-Integer 
zusammenbauen, das x 5x hintereinander in einen Integer packen, XOR auf 
beide Werte, und dann das 0-Byte finden.

Autor: A. S. (achs)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter, Du müsstest schon etwas über Kontext und Anwendung schreiben. 
Sonst geht z.B. auch sowas:
char *vokale="aeiou";
char *p =strchar(vokale, x);
 
    if(p)
    {
        x=(vokale-p)+'1';
    }
Macht für Dich aber höchstwahrscheinlich wenig Sinn.

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter schrieb:
> Hi
>
> Ich habe folgendes Array definiert:
>
> char compare[5][2]={
>   {'a', '1'},
>   {'e', '2'},
>   {'i', '3'},
>   {'o', '4'},
>   {'u', '5'}
> }
> 
>
> ich möchte nun die Variabel x überprüfen of sie a,e,i,o oder u beträgt,
> und den entsprechenden in der 2. Spalte im array Wert zuweisen.
>
> momentan habe ich es so gelöst:
>
> for (int i=0; i<5; i++)
> {
>   if (x== compare[i][0])
>   {
>       x = compare[i][1];
>   }
> }
> 
>
>
> geht dies auch einfacher zu lösen ohne jedesmal mit einer for Schleife
> das ganze array zu durchforsten?

Das iterative Suchen kannst Du mit einer vollständigen LUT vermeiden 
(s.a. Variante1).

Statt einer Iteration über eine Teilbereichs-LUT kann Du auch eine Folge 
von Alternativen (if-statements) verwenden. Mit etwas TMP ist diese 
Folge von if-statements auch automatisch abhängig von der Größe Deine 
LUT (s.a. Variante 2).

#include <iostream>
#include <array>
#include <numeric>
#include <algorithm>

struct Converter1 {
    inline static auto transformVowel(const char c) {
        return lut[c];
    }
private:
    inline static const auto lut = []{
        std::array<char, 256> lut{};
        std::iota(std::begin(lut), std::end(lut), char{0});
        lut['a'] = '1';
        lut['e'] = '2';
        lut['i'] = '3';
        lut['o'] = '4';
        lut['u'] = '5';
        return lut;
    }();
};

struct Converter2 {
    inline static char constexpr transformVowel(const char c) {
        return [&]<auto... II>(std::index_sequence<II...>){
            char r{c};
            (((c == lut[II].first) ? (r = lut[II].second) : c), ...);
            return r;
        }(std::make_index_sequence<std::size(lut)>{});
    }
private:
    inline static constexpr std::array<std::pair<char, char>, 5> lut{{{'a', '1'}, {'e', '2'}, {'i', '3'}, {'o', '4'}, {'u', '5'}}};
};


int main(){
    std::string result;
    std::string text{"Dies ist ein Test.\n"};
    
    // Variante 1
    std::transform(std::begin(text), std::end(text), std::back_inserter(result), Converter1::transformVowel);

    // Variante 2
    std::transform(std::begin(text), std::end(text), std::back_inserter(result), Converter2::transformVowel);

    std::cout << result;
}

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.