Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Das Programmier-Spiel: nette Übungsaufgaben für zwischendurch
dN!3L
myCSharp.de - Experte

Avatar #avatar-2985.png


Dabei seit:
Beiträge: 3138

beantworten | zitieren | melden

Zitat von edsplash
stellt quasi eine 1:1 Verknüpfung, bzw. eine eindeutige Zuordnung
*klugscheiß* Du meinst eineindeutig!? Als bijektiv (rechtseindeutig/surjektiv und linkseindeutig/injektiv).
private Nachricht | Beiträge des Benutzers
inflames2k
myCSharp.de - Experte

Avatar #AARsmmPEUMee0tQa2JoB.png


Dabei seit:
Beiträge: 2340

beantworten | zitieren | melden

Um Exceptionhandling hab ich mich nun aber nicht gekümmert. War auch wenn ich mich nicht verlesen hab kein Teil der Aufgabe. :)

Hoffe das passt so.


class IMapClass : IMap<String, Object>
{
	#region IMap<T,T> Member

	List<String> _leftList = new List<String>();
	List<Object> _rightList = new List<object>();

	public void Add(String leftItem, Object rightItem)
	{
		if (!this._leftList.Contains(leftItem) 
			&& !this._rightList.Contains(rightItem))
		{
			this._leftList.Add(leftItem);
			this._rightList.Add(rightItem);
		}
		else
		{
			throw new InvalidOperationException("Zuordnung nicht möglich, ein Objekt darf nur einmal vorkommen.");
		}
	}

	public Object this[String item]
	{
		get
		{
			return this._rightList[_leftList.IndexOf(item)];			
		}
		set
		{
                        if(!_rightList.Contains(item))
				this._rightList[_leftList.IndexOf(item)] = value;
                        else 
                                throw new InvalidOperationException("Das Objekt existiert bereits bei einer anderen Zuordnung.");
		}
	}
	public String this[Object item]
	{
		get
		{
			return this._leftList[_rightList.IndexOf(item)];
		}
		set
		{
                        if(!_leftList.Contains(item)=
				this._leftList[_rightList.IndexOf(item)] = value;
                        else 
                                throw new InvalidOperationException("Das Objekt existiert bereits bei einer anderen Zuordnung.");
		}
	}

	public bool Contains(String item)
	{
		return _leftList.Contains(item);
	}

	public bool Contains(Object item)
	{
		return _rightList.Contains(item);
	}

	public bool Remove(String item)
	{			
		return this._rightList.Remove(_rightList[_leftList.IndexOf(item)]) && this._leftList.Remove(item);			
	}

	public bool Remove(Object item)
	{
		return this._leftList.Remove(_leftList[_rightList.IndexOf(item)]) && this._rightList.Remove(item);
	}

	public void Clear()
	{
		this._leftList.Clear();
		this._rightList.Clear();
	}

	public int Count
	{
		get { return this._leftList.Count; }
	}

	#endregion
}


Für Meinungen bin ich natürlich offen.
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von inflames2k am .
Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager | Spielkartenbibliothek
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo inflames2k,
Zitat
Um Exceptionhandling hab ich mich nun aber nicht gekümmert. War auch wenn ich mich nicht verlesen hab kein Teil der Aufgabe. :)
nö, aber es war verlangt, dass Objekte nicht mehrfach vorkommen können. Das hast du zwar bei Add berücksichtigt, aber an anderen Stellen nicht.


Hallo edsplash,

wo ich eh gerade einen Beitrag schreibe:
Zitat
Man sollte dabei sofern möglich vermeiden auf .NET Klassen wie Dictionary<T>, HashSet<T> zurück zu greifen.
Da hast du ja was schönes erreicht. inflames2k hat List <T>genommen (und wenn auch das nicht erlaubt gewesen wäre, dann vermutlich Array, irgendworauf wird man ja sinnvollerweise aufbauen). Dadurch ist deine Bedingung formal erfüllt. Aber was hast du erreicht? Der Code ist auch nicht länger oder komplizierter als wenn man Dictionary<> verwendet hätte, aber um Größenordnungen weniger performant.

herbivore
private Nachricht | Beiträge des Benutzers
inflames2k
myCSharp.de - Experte

Avatar #AARsmmPEUMee0tQa2JoB.png


Dabei seit:
Beiträge: 2340

beantworten | zitieren | melden

Stimmt, gab ja noch die Zuordnung per Objekt[key]. - Hab es im Code angepasst.
Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager | Spielkartenbibliothek
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo inflames2k,

dein Code trifft es immer noch nicht. Du musst ja auf jeden Fall auch value prüfen. Außerdem muss es erlaubt sein, einem Objekt das bereits zugeordnete Objekt erneut zuzuordnen. Überlegt dir nochmal genau, welche Fälle alle auftreten können.

BTW: warum hast du die Klasse denn für konkrete Typen implementiert? Statt class IMapClass : IMap<String, Object> wäre Map<TLeft, TRight> : IMap<TLeft, TRight> deutlich sinnvoller gewesen (mal ganz abgesehen davon, dass Klassennamen keinen Präfix haben sollten, erst recht nicht den Präfix I).

herbivore
private Nachricht | Beiträge des Benutzers
inflames2k
myCSharp.de - Experte

Avatar #AARsmmPEUMee0tQa2JoB.png


Dabei seit:
Beiträge: 2340

beantworten | zitieren | melden

Naja, stimmt so wohl auch wieder.

value hatte ich im Visual Studio geprüft wohl aber hier in der Änderung vergessen dies zu ändern.

Das mit der neu Zuordnung des selben Objektes stimmt so natürlich auch wieder. - Den Fall hatte ich nicht bedacht.

Konkrete Typen habe ich genommen, nachdem mein Compiler begann mir vorwürfe zu machen.

Nun aber die Volle und nun denk ich richtigere Variante:


	class Map<TLeft, TRight> : IMap<TLeft, TRight>
	{
		#region IMap<TLeft,TRight> Member

		List<TLeft> _leftList = new List<TLeft>();
		List<TRight> _rightList = new List<TRight>();

		public void Add(TLeft leftItem, TRight rightItem)
		{
			if (!_leftList.Contains(leftItem) && !_rightList.Contains(rightItem))
			{
				_leftList.Add(leftItem);
				_rightList.Add(rightItem);
			}
			else
				throw new InvalidOperationException("Ein Objekt kann nicht mehrfach zugeordnet werden.");
		}

		public TRight this[TLeft item]
		{
			get
			{
				return _rightList[_leftList.IndexOf(item)];
			}
			set
			{
				if(!_rightList.Contains(value) || _rightList[_leftList.IndexOf(item)].Equals(value))
					_rightList[_leftList.IndexOf(item)] = value;
				else throw new InvalidOperationException("Objekt ist bereits in der Zuordnung vorhanden.");
			}
		}

		public TLeft this[TRight item]
		{
			get
			{
				return _leftList[_rightList.IndexOf(item)];
			}
			set
			{
				if (!_leftList.Contains(value) || _leftList[_rightList.IndexOf(item)].Equals(value))
					_leftList[_rightList.IndexOf(item)] = value;
				else throw new InvalidOperationException("Objekt ist bereits in der Zuordnung vorhanden.");
			}
		}

		public bool Contains(TLeft item)
		{
			return _leftList.Contains(item);
		}

		public bool Contains(TRight item)
		{
			return _rightList.Contains(item);
		}

		public bool Remove(TLeft item)
		{
			return _rightList.Remove(_rightList[_leftList.IndexOf(item)]) && _leftList.Remove(item);
		}

		public bool Remove(TRight item)
		{
			return _leftList.Remove(_leftList[_rightList.IndexOf(item)]) && _rightList.Remove(item);
		}

		public void Clear()
		{
			_leftList.Clear();
			_rightList.Clear();
		}

		public int Count
		{
			get { return _leftList.Count; }
		}

		#endregion
	}
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von inflames2k am .
Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager | Spielkartenbibliothek
private Nachricht | Beiträge des Benutzers
edsplash
myCSharp.de - Member

Avatar #avatar-3111.jpg


Dabei seit:
Beiträge: 411

beantworten | zitieren | melden

Hallo herbivore
Zitat von herbivore
Da hast du ja was schönes erreicht. inflames2k hat List <T>genommen (und wenn auch das nicht erlaubt gewesen wäre, dann vermutlich Array, irgendworauf wird man ja sinnvollerweise aufbauen). Dadurch ist deine Bedingung formal erfüllt. Aber was hast du erreicht? Der Code ist auch nicht länger oder komplizierter als wenn man Dictionary<> verwendet hätte, aber um Größenordnungen weniger performant.

[offtopic]
Hehe, ich hatte gedacht, jemand würde es ohne Dictionary ähnlich performant hinkriegen ;) Mit dem Dictionary wird der Code allerdings weniger komplex, vorallem wenn man zwei davon verwendet -> Dictionary<TLeft, TRight> und Dictionar<TRight, TLeft>.
[/offtopic]

Hallo inflames2k

Deine Lösung scheint korrekt zu sein!
using Skill
private Nachricht | Beiträge des Benutzers
TheBrainiac
myCSharp.de - Member

Avatar #avatar-3152.png


Dabei seit:
Beiträge: 832
Herkunft: /dev/null

beantworten | zitieren | melden

Gnahh... Schon wieder zu langsam....

Gefragt war aber auch, die Implementierung ohne die Generischen Listen / Dictionaries aus System.Collections.Generic.

Hier ist meine Lösung:

public class Map<TLeft, TRight> : IMap<TLeft, TRight>
{
	private TLeft[] m_Left = null;
	private TRight[] m_Right = null;
	private Boolean[] m_Used = null;
	private Int32 m_Count = 0;
	
	public Map()
	    : this(100) { }
	
	public Map(Int32 startCapacity) {
		m_Left = new TLeft[startCapacity];
		m_Right = new TRight[startCapacity];
		m_Used = new Boolean[startCapacity];
	}
	
	/// <summary>
    /// Fügt der Map eine Zuordnung hinzu
    /// </summary>
    public void Add(TLeft leftItem, TRight rightItem) {
        if (Contains(leftItem)) {
            throw new ArgumentException("Item already added!", "leftItem");
        }
        
        if (Contains(rightItem)) {
            throw new ArgumentException("Item already added!", "rightItem");
        }
        
        Int32 index = GetNextFreeIndex();
        
        m_Used[index] = true;
        m_Left[index] = leftItem;
        m_Right[index] = rightItem;
        m_Count++;
	}

    /// <summary>
    /// Liest ein Element auf der rechten Seite der Map aus oder setzt dieses
    /// </summary>
    /// <param name="item">Ein Element auf der linken Seite, welches als Schlüssel dient</param>
    public TRight this[TLeft item] {
        get {
            Int32 idx = Find(item);
            
            if (idx == -1) {
                throw new KeyNotFoundException("Item not found!");
            }
            
            return m_Right[idx];
        }
        set {
            if (Contains(value)) {
                throw new ArgumentException("Item already added!", "value");
            }
            
            Int32 idx = Find(item);
            
            if (idx == -1) {
                Add(item, value);
            } else {
                m_Right[idx] = value;
            }
        }
    }

    /// <summary>
    /// Liest ein Element auf der linken Seite der Map aus oder setzt dieses
    /// </summary>
    /// <param name="item">Ein Element auf der rechten Seite, welches als Schlüssel dient</param>
    public TLeft this[TRight item] {
        get {
            Int32 idx = Find(item);
            
            if (idx == -1) {
                throw new KeyNotFoundException("Item not found!");
            }
            
            return m_Left[idx];
        }
        set {
            if (Contains(value)) {
                throw new ArgumentException("Item already added!", "value");
            }
            
            Int32 idx = Find(item);
            
            if (idx == -1) {
                Add(value, item);
            } else {
                m_Left[idx] = value;
            }
        }
    }

    /// <summary>
    /// Gibt an, ob auf der linken Seite ein spezifisches Element vorhanden ist
    /// </summary>
    public Boolean Contains(TLeft item) {
        return Find(item) != -1;
    }

    /// <summary>
    /// Gibt an, ob auf der rechten Seite ein spezifisches Element vorhanden ist
    /// </summary>
    public Boolean Contains(TRight item) {
        return Find(item) != -1;
    }

    /// <summary>
    /// Löscht eine Zuordnung
    /// </summary>
    /// <param name="item">Ein Element auf der linken Seite, welches als Schlüssel dient</param>
    public Boolean Remove(TLeft item) {
        return Remove(Find(item));
    }

    /// <summary>
    /// Löscht eine Zuordnung
    /// </summary>
    /// <param name="item">Ein Element auf der rechten Seite, welches als Schlüssel dient</param>
    public Boolean Remove(TRight item) {
        return Remove(Find(item));
    }

    /// <summary>
    /// Löscht alle Zuordnungen
    /// </summary>
    public void Clear() {
        m_Used = new Boolean[m_Used.Length];
        m_Left = new TLeft[m_Left.Length];
        m_Right = new TRight[m_Right.Length];
    }

    /// <summary>
    /// Gibt die Anzahl der vorhandenen Zuordnungen zurück
    /// </summary>
    public Int32 Count {
        get {
            return m_Count;
        }
    }
    
    private Boolean Remove(Int32 idx) {
        if (idx < 0 || idx > m_Used.Length || !m_Used[idx]) {
            return false;
        }
        
        m_Used[idx] = false;
        m_Left[idx] = default(TLeft);
        m_Right[idx] = default(TRight);
        
        m_Count--;
        
        return true;
    }
    
    private Int32 GetNextFreeIndex() {
        for (Int32 i = 0; i < m_Used.Length; i++) {
            if (!m_Used[i]) {
                return i;
            }
        }
        
        EnlargeArrays();
        
        return GetNextFreeIndex();
    }
    
    private void EnlargeArrays() {
        Boolean[] tmpUsed = m_Used;
        TLeft[] tmpLeft = m_Left;
        TRight[] tmpRight = m_Right;
        
        m_Used = new Boolean[tmpUsed.Length * 2];
        m_Left = new TLeft[tmpLeft.Length * 2];
        m_Right = new TRight[tmpRight.Length * 2];
        
        tmpUsed.CopyTo(m_Used, 0);
        tmpLeft.CopyTo(m_Left, 0);
        tmpRight.CopyTo(m_Right, 0);
    }
    
    private Int32 Find(TLeft item) {
        for (Int32 i = 0; i < m_Used.Length; i++) {
            if (m_Used[i] && m_Left[i].Equals(item)) {
                return i;
            }
        }
        
        return -1;
    }
    
    private Int32 Find(TRight item) {
        for (Int32 i = 0; i < m_Used.Length; i++) {
            if (m_Used[i] && m_Right[i].Equals(item)) {
                return i;
            }
        }
        
        return -1;
    }
}

Gruß, Christian.
Dieser Beitrag wurde 3 mal editiert, zum letzten Mal von TheBrainiac am .
There are 10 types of people in the world:
Those, who think they understand the binary system
Those who don't even have heard about it
And those who understand "Every base is base 10"
private Nachricht | Beiträge des Benutzers
inflames2k
myCSharp.de - Experte

Avatar #AARsmmPEUMee0tQa2JoB.png


Dabei seit:
Beiträge: 2340

beantworten | zitieren | melden

Gut, eine Aufgabe gibt es sobald mir etwas eingefallen ist. - Hatte zwar gerade einen Gedanken aber den müsst ich erstmal selbst für mich zusammen fassen.

Esseidenn dir fällt eine gute Aufgabe ein Schamese. :-) - Dann darfst du sie auch gern stellen.

Vermieden werden sollten Dictionary und HashSet, nicht alle Generics, aufgrund der Funktionalitäten die vom Dictionary Beispielsweise schon gegeben sind.

Wobei das nun auch unrelevant wäre. - Wie herbivore sagte, performant ist das nicht.
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von inflames2k am .
Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager | Spielkartenbibliothek
private Nachricht | Beiträge des Benutzers
TheBrainiac
myCSharp.de - Member

Avatar #avatar-3152.png


Dabei seit:
Beiträge: 832
Herkunft: /dev/null

beantworten | zitieren | melden

Hi @ All.

Nach Absprache mit inflames2k darf ich nun eine Aufgabe stellen.

Entwickle einen kleinen Parser & Interpreter für simple mathematische Formeln.
Er soll folgendes beherrschen:
  • Addieren, Subtrahieren, Multiplizieren und Dividieren von Integer-Literalen.
  • Terme sollen mit Klammern zusammengefasst werden können.
  • Der Interpreter soll das Ergebnis des eingegebenen Terms berechnen.
  • Variablen, Funktionen und symbolische Konstanten brauchen nicht eingebaut werden.

Natürlich soll man seinen eigenen Parser/Interpreter schreiben. Parser-Generatoren, Vorgefertigte Interpreter, Scripting-Engines, Regex etc. sind nicht erlaubt. Ebenso gilt der Parser für mathematische Formeln nicht und darf auch nicht als Vorlage benutzt werden.

Gruß & Viel Spaß,
Christian.
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von TheBrainiac am .
There are 10 types of people in the world:
Those, who think they understand the binary system
Those who don't even have heard about it
And those who understand "Every base is base 10"
private Nachricht | Beiträge des Benutzers
Th69
myCSharp.de - Experte

Avatar #avatar-2578.jpg


Dabei seit:
Beiträge: 4001

beantworten | zitieren | melden

Na, dann darf ich ja wohl nicht mitmachen
private Nachricht | Beiträge des Benutzers
TheBrainiac
myCSharp.de - Member

Avatar #avatar-3152.png


Dabei seit:
Beiträge: 832
Herkunft: /dev/null

beantworten | zitieren | melden

Hi @ All.

Ich habe auf den Rat von herbivore die Aufgabenstellung noch einmal angepasst.

Gruß, Christian.
There are 10 types of people in the world:
Those, who think they understand the binary system
Those who don't even have heard about it
And those who understand "Every base is base 10"
private Nachricht | Beiträge des Benutzers
MarsStein
myCSharp.de - Experte

Avatar #avatar-3191.gif


Dabei seit:
Beiträge: 3429
Herkunft: Trier -> München

beantworten | zitieren | melden

Hallo,

ich glaub das müsste es bringen:

using System;
using System.Collections.Generic;

namespace TestApp
{
  class Program
  {
    static double Calc(string input)
    {
// die folgende Zeile wiede4r einkommentieren um das Verfahren zu sehen
//    Console.WriteLine(input); 
      input = input.Trim();
      if(input.Length > 0)
      {
        int open = input.LastIndexOf('(');
        if(open ≥ 0)
        {
          int match = input.IndexOf(')',open);
          if(match > open)
          {
            double partRes = Calc(input.Substring(open+1, match-open-1));
            if(partRes != double.NaN)
            {
              return Calc(input.Remove(open, match-open+1).Insert(open, partRes.ToString()));
            }
          }
        }
        else
        {
          if(char.IsDigit(input[input.Length-1]))
          {
            int pos = input.IndexOf('+');
            if(pos > 0)
            {
              return Calc(input.Substring(0,pos)) + Calc(input.Substring(pos+1));
            }
            pos = input.IndexOf('-');
            if((pos > 0) && (Char.IsDigit(input[pos-1]))) // <<< hier das IsDigit eingebaut
            {
              return Calc(input.Substring(0,pos)) - Calc(input.Substring(pos+1));
            }
            pos = input.IndexOf('*');
            if(pos > 0)
            {
              return Calc(input.Substring(0,pos)) * Calc(input.Substring(pos+1));
            }
            pos = input.IndexOf('/');
            if(pos > 0)
            {
              return Calc(input.Substring(0,pos)) / Calc(input.Substring(pos+1));
            }
            double result;
            if(double.TryParse(input, out result))
            {
              return result;
            }
          }
        }
      }
      return double.NaN;
    }
    
    public static void Main(string[] args)
    {
      do
      {
        Console.WriteLine("Term eingeben:");
        double result = Calc(Console.ReadLine());
        Console.WriteLine("Ergebnis: " + result.ToString());
        Console.WriteLine();
        Console.WriteLine("Leertaste zum Beenden, andere Taste zum Fortfahren");
      }while(Console.ReadKey().Key != ConsoleKey.Spacebar);
    }
  }
}

Edit: erlaubt sind nur die runden Klammern "()". Bei Fehleingaben müsste immer NaN zurückgegeben werden.

EDIT 2: Der Code hat nicht funktioniert, wenn innerhalb eines Klammerpaars eine negative Zahl herauskam. Ich habe die korrigierte Stelle oben markiert (Prüfung auf IsDigit vor einem '-')

Gruß, MarsStein
Dieser Beitrag wurde 3 mal editiert, zum letzten Mal von MarsStein am .
Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca
private Nachricht | Beiträge des Benutzers
Gelöschter Benutzer

beantworten | zitieren | melden

das da:

if(partRes != double.NaN)

ist immer true. also kannst du es auch gleich weglassen, was dir dann immernoch das problem übriglässt, das partRes noch NaN sein könnte. aber fehleingaben sind ja keine bedingung. ich wollte es nur mal erwähnt wissen :-)

gib mal "-(10*5/6+(-5*7))" ein ;-)
MarsStein
myCSharp.de - Experte

Avatar #avatar-3191.gif


Dabei seit:
Beiträge: 3429
Herkunft: Trier -> München

beantworten | zitieren | melden

Hallo,
Zitat von JAck30lena
das da: if(partRes != double.NaN)ist immer true.
Wenn Du den von Dir genannten Term eingibst, und zusätzlich innerhalb des if mal eine Konsolenausgabe machst, siehst Du, dass Du damit fasch liegst.

Trotzdem hast Du natürlich recht: da ist noch ein Fehler drin. Kümmere mich bald darum -> keine Zeit jetzt.

Gruß, MarsStein
Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca
private Nachricht | Beiträge des Benutzers
Gelöschter Benutzer

beantworten | zitieren | melden

sry... nein. ;-)

versuch mal:

            string nurUmOptimierungenZuVermeiden = Console.ReadLine();
            double d = double.NaN;
            if(d == double.NaN) Console.WriteLine("hier ist double ein NaN \n" + nurUmOptimierungenZuVermeiden);
MarsStein
myCSharp.de - Experte

Avatar #avatar-3191.gif


Dabei seit:
Beiträge: 3429
Herkunft: Trier -> München

beantworten | zitieren | melden

Hallo Jack30lena,

du hast natürlich recht ;) habs jetzt auf double.IsNaN umgestellt, und das Problem mit "-(" dadurch behoben, dass es durch "-1*(" ersetzt wird:

using System;

namespace TestApp
{
  class Program
  {
    static double Calc(string input)
    {
      // die folgende Zeile wiede4r einkommentieren um das Verfahren zu sehen
      //    Console.WriteLine(input);
      input = input.Trim();
      if (input.Length > 0)
      {
        int open = input.LastIndexOf('(');
        if (open ≥ 0)
        {
          int match = input.IndexOf(')', open);
          if (match > open)
          {
            double partRes = Calc(input.Substring(open + 1, match - open - 1));
            // partRes = double.NaN;  <<< die böse Zeile (siehe Folgebeiträge)
            if (!double.IsNaN(partRes))
            {
              return Calc(input.Remove(open, match - open + 1).Insert(open, partRes.ToString()));
            }
          }
        }
        else if (char.IsDigit(input[input.Length - 1]))
        {
          int pos = input.IndexOf('+');
          if (pos > 0)
          {
            return Calc(input.Substring(0, pos)) + Calc(input.Substring(pos + 1));
          }
          pos = input.IndexOf('-');
          if ((pos > 0) && (Char.IsDigit(input[pos - 1]))) // <<< hier das IsDigit eingebaut
          {
            return Calc(input.Substring(0, pos)) - Calc(input.Substring(pos + 1));
          }
          pos = input.IndexOf('*');
          if (pos > 0)
          {
            return Calc(input.Substring(0, pos)) * Calc(input.Substring(pos + 1));
          }
          pos = input.IndexOf('/');
          if (pos > 0)
          {
            return Calc(input.Substring(0, pos)) / Calc(input.Substring(pos + 1));
          }
          double result;
          if (double.TryParse(input, out result))
          {
            return result;
          }
        }
      }
      return double.NaN;
    }

    static double Parse(String input) { 
      return Calc(input.Replace("-(", "-1*("));
    }

    public static void Main(string[] args)
    {
      do
      {
        Console.WriteLine("Term eingeben:");
        double result = Parse(Console.ReadLine());
        Console.WriteLine("Ergebnis: " + result.ToString());
        Console.WriteLine();
        Console.WriteLine("Leertaste zum Beenden, andere Taste zum Fortfahren");
      } while (Console.ReadKey().Key != ConsoleKey.Spacebar);
    }
  }
}

sonst noch irgenwelche Fehler?

Gruß, MarsStein
Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca
private Nachricht | Beiträge des Benutzers
Gelöschter Benutzer

beantworten | zitieren | melden

ich kann keine fehler mehr feststellen. wunderschöne lösung. respekt :-)
TheBrainiac
myCSharp.de - Member

Avatar #avatar-3152.png


Dabei seit:
Beiträge: 832
Herkunft: /dev/null

beantworten | zitieren | melden

Ich hab aber doch noch einen Fehler gefunden:

Gib mal (12+1)*2 ein... --> Heraus kommen sollte 26, aber es kommt NaN raus...

Gruß, Christian.

//EDIT Irgendie kommt bei mir immer wenn eine Klammer drin ist n. def. raus...
Dieser Beitrag wurde 4 mal editiert, zum letzten Mal von TheBrainiac am .
There are 10 types of people in the world:
Those, who think they understand the binary system
Those who don't even have heard about it
And those who understand "Every base is base 10"
private Nachricht | Beiträge des Benutzers
Cat
myCSharp.de - Member

Avatar #avatar-3070.jpg


Dabei seit:
Beiträge: 790

beantworten | zitieren | melden

Die Zeile


partRes = double.NaN;
ist wohl dafür verantwortlich (wahrscheinlich noch der Test wegen den NaN-Beiträgen vorher -)
private Nachricht | Beiträge des Benutzers
MarsStein
myCSharp.de - Experte

Avatar #avatar-3191.gif


Dabei seit:
Beiträge: 3429
Herkunft: Trier -> München

beantworten | zitieren | melden

Hallo,

in der Tat ist es genau so wie Cat schrieb: Da ist mir 'ne Zeile vom Testen stehengeblieben. Ich editiere das gleich oben im Code und mache die Stelle dort auch kenntlich. Danach sollte aber alles laufen ;)
Die nächste Aufgabe gibt's dann heut abend.

Gruß, MarsStein
Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca
private Nachricht | Beiträge des Benutzers
TheBrainiac
myCSharp.de - Member

Avatar #avatar-3152.png


Dabei seit:
Beiträge: 832
Herkunft: /dev/null

beantworten | zitieren | melden

Hallo, MarsStein.

Stimmt. Wenn ich die Zeile Raus nehme, funktioniert's einwandfrei.

Wie JAck30lena schon gesagt hat:
Zitat von JAck30lena
ich kann keine fehler mehr feststellen. wunderschöne lösung. respekt :-)

Damit bist du dran!

Gruß, Christian.
There are 10 types of people in the world:
Those, who think they understand the binary system
Those who don't even have heard about it
And those who understand "Every base is base 10"
private Nachricht | Beiträge des Benutzers
MarsStein
myCSharp.de - Experte

Avatar #avatar-3191.gif


Dabei seit:
Beiträge: 3429
Herkunft: Trier -> München

beantworten | zitieren | melden

Hallo,
Zitat von JAck30lena
wunderschöne lösung. respekt :-)
danke dafür und für den Hinweis wegen NaN
Rekursion mal von hinten nach vorn und von innen nach außen

Dann mal die nächste Aufgabe:
erstellt ein Programm, das eine vom Benutzer wählbare Anzahl von Kugeln nach dem Prinzip des Galtonbretts auf einzelne Fächer verteilt. Die Anzahl der Stufen des Bretts soll ebenfalls vom Benutzer gewählt werden können (denkt daran, daß es ein Fach mehr als Stufen gibt).
Die dabei erzeugte Verteilung soll in einem Balkendiagramm (1 Balken je Fach) sinnvoll skaliert* ausgegeben werden. Die Balken sollen mit der entsprechenden Trefferzahl beschriftet werden.
Die Aufgabe ist mit der Ausgabe von waagerechten Balken auf der Konsole erfüllt.

Gruß, MarsStein

*Edit: Sinnvoll skaliert bezieht sich auf sinnvolle Eingabebereiche (die nicht geprüft werden müssen), bei denen die Anzahl der Kugeln viel größer als die Anzahl der Fächer ist, und die maximale Anzahl der Fächer im Bereich der Zeilenzahl der Konsole liegt.
Ich erwarte aber, daß die maximale Länge der Balken mit steigender Anzahl an Fächern mitwächst, die Kurve also halbwegs mitskaliert wird.
Dieser Beitrag wurde 3 mal editiert, zum letzten Mal von MarsStein am .
Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca
private Nachricht | Beiträge des Benutzers
talla
myCSharp.de - Experte

Avatar #avatar-3214.jpg


Dabei seit:
Beiträge: 7290
Herkunft: Esslingen

beantworten | zitieren | melden

Hallo,

hier mal ne kurze Lösung von mir weil ich auch mal ne Aufgabe stellen möchte :)


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace Galton {
    class Program {
        static void Main(string[] args) {

            Console.Write("Geben Sie die Anzahl der Stufen an: ");
            var stufen = Convert.ToInt32(Console.ReadLine());
            Console.Write("Geben sie die Anzahl der Kugeln an: ");
            var kugeln = Convert.ToInt32(Console.ReadLine());

            Galton g = new Galton(stufen);
            var bins = g.DropBalls(kugeln);

            PrintResults(3, bins);

            Console.ReadLine();
        }

        static void PrintResults(int startY, int[] bins) {

            // Skalierungsfaktor anhand der größten Kugelmenge berechnen
            var scale = 75.0 / bins.Max();

            for (int i = 0; i < bins.Length - 1; i++) {
                // Anzahl zu druckender Zeichen bestimmen
                var end = (int)(bins[i] * scale);

                for (int j = 0; j < end; j++) {
                    Console.SetCursorPosition(j, startY + i*2);
                    Console.Write("x");
                }

                // Noch die Anzahl der Kugeln an den Anfang schreiben
                Console.SetCursorPosition(0, startY + i*2);
                Console.Write(String.Format("{0} ",bins[i]));
            }
        }
    }

    public class Galton {
        List<double> factors = new List<double>();
        Random rand = new Random();
        double sum;

        public Galton(int level) {
            Func<Decimal, Decimal> factorial = null;
            Func<Decimal, Decimal, Decimal> binom = null;

            // Fakultät
            factorial = (n) => (n == 0) ? 1 : n * factorial(n - 1);
            // Binomialkoeffizenten
            binom = (n, k) => factorial(n) / (factorial(k) * factorial(n - k));

            sum = Math.Pow(2.0, level);

            foreach (var i in Enumerable.Range(0, level + 1)) {
                factors.Add(Convert.ToDouble(binom(level, i)));
            }

            // Summen für jedes Fach aufaddieren, siehe DropBalls für warum
            factors = factors.Aggregate(
                new List<double>() { 0 },
                (acc, item) => {
                    acc.Add(acc[acc.Count - 1] + item);
                    return acc;
                }
                , (acc) => acc).ToList();
        }

        public int[] DropBalls(int balls) {
            // Fächer
            int[] bins = new int[factors.Count];

            // für jeden gezogenen Ball...
            for (int i = 0; i < balls; i++) {
                // Zufallszahl erzeugen
                var num = rand.NextDouble()*sum;
                // Fächersummen durchgehen wenn Zufallszahl kleiner als Summe, ist die Kugel ins vorherige Fach gefallen
                for (int j = 0; j < factors.Count; j++) {
                    if (num < factors[j]) {
                        bins[j-1]++;
                        break;
                    }
                }
            };
            return bins;
        }
    }
}

Zitat von MarsStein
*Edit: Sinnvoll skaliert bezieht sich auf sinnvolle Eingabebereiche (die nicht geprüft werden müssen), bei denen die Anzahl der Kugeln viel größer als die Anzahl der Fächer ist, und die maximale Anzahl der Fächer im Bereich der Zeilenzahl der Konsole liegt.
Ich erwarte aber, daß die maximale Länge der Balken mit steigender Anzahl an Fächern mitwächst, die Kurve also halbwegs mitskaliert wird.

Ich erfülle diese Erwartung mit Absicht nicht - ob du die Aufgabe als gelöst erklärst ist dir überlassen. Der Grund ist einfach der, dass ich darin keinen Sinn sehe. Die Zeichenzahl in der Konsole pro Zeile ist so gering das man eh schon kaum gescheit skalieren kann. Wenn man bei wenigen Fächern die Balken kürzer macht, erkennt man bei Angabe der Kugeln in den Fächern gar nichts mehr.
Baka wa shinanakya naoranai.

Mein XING Profil.
private Nachricht | Beiträge des Benutzers
MarsStein
myCSharp.de - Experte

Avatar #avatar-3191.gif


Dabei seit:
Beiträge: 3429
Herkunft: Trier -> München

beantworten | zitieren | melden

Hallo talla,

da die Skalierung ausdrücklich gefordert war, kann ich Deine Lösung leider so nicht durchgehen lassen
Diese eine Mutiplikation wirst Du schon noch einbauen müssen, wenn Du die nächste Aufgabe stellen möchtest...
Ich habe auch einen Grund dafür: Wenn die Balken an der Zeilenzahl skaliert werden, sind die Kurven von der Form her vergleichbarer, und die Gleichverteilung bei verschiedenen Eingaben läßt sich besser erkennen. Als Beispiel mal die Ausgabe meiner eigenen Lösung, ich denke das veranschaulicht das etwas:
Galtonbrett Simulation

Stufen: 8
Kugeln: 10000
  35 -
 297 -
1134 ----
2126 --------
2701 ---------
2252 --------
1088 ----
 321 --
  46 -

Stufen: 12
Kugeln: 100000
   20 -
  264 -
 1627 -
 5466 ----
12097 -------
19259 ------------
22551 -------------
19199 ------------
12198 --------
 5361 ----
 1630 -
  299 -
   29 -

Stufen: 16
Kugeln: 1000000
    20 -
   228 -
  1835 -
  8443 -
 27608 ---
 66411 ------
122927 -----------
174475 ----------------
196019 -----------------
175201 ----------------
121609 -----------
 66909 ------
 27857 ---
  8379 -
  1802 -
   255 -
    22 -

Gruß, MarsStein
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von MarsStein am .
Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca
private Nachricht | Beiträge des Benutzers
talla
myCSharp.de - Experte

Avatar #avatar-3214.jpg


Dabei seit:
Beiträge: 7290
Herkunft: Esslingen

beantworten | zitieren | melden

Hallo,

hier die geänderte Ausgabefunktion:

        static void PrintResults(int startY, int[] bins) {
            var max = Convert.ToDouble(bins.Max());
            var baseChars = 10.0;
            // skalieren mit dem 10er Logarithmus des Maximums
            var log = (int)Math.Log10(max);
            for (int i = 0; i < log; i++) {
                baseChars += 5.0;
            }

            // Skalierungsfaktor anhand der größten Kugelmenge berechnen
            var scale = baseChars / bins.Max();
            var offset = 10;

            for (int i = 0; i < bins.Length - 1; i++) {
                // Anzahl zu druckender Zeichen bestimmen
                var end = (int)(bins[i] * scale);

                for (int j = 0; j < end; j++) {
                    Console.SetCursorPosition(offset + j, startY + i*2);
                    Console.Write("x");
                }

                // Noch die Anzahl der Kugeln an den Anfang schreiben
                Console.SetCursorPosition(0, startY + i*2);
                Console.Write(bins[i]);
            }
        }

Wobei ich die Skalierung immer noch vollkommen irreführend finde. Gerade in deinem letzten Beispiel sieht man das gut. Sowohl das erste Fach mit 20, als auch das 4. mit 8443 Kugeln, werden mit jeweils nur einer Einheit dargestellt. Wenn man von ganz weit weg schaut, sieht man zwar die entstehende Binomialverteilung, aber die Kurve stimmt vorne und hinten nicht in der Darstellung (was natürlich an der Konsole liegt als Ausgabemedium).
Baka wa shinanakya naoranai.

Mein XING Profil.
private Nachricht | Beiträge des Benutzers
MarsStein
myCSharp.de - Experte

Avatar #avatar-3191.gif


Dabei seit:
Beiträge: 3429
Herkunft: Trier -> München

beantworten | zitieren | melden

Hallo talla,

Über den SInn und Unsinn der Skalierung kann man sicherlich streiten, vor allem hast Du recht mit Deinen Aussagen:
Zitat
Gerade in deinem letzten Beispiel sieht man das gut. Sowohl das erste Fach mit 20, als auch das 4. mit 8443 Kugeln, werden mit jeweils nur einer Einheit dargestellt.
und
Zitat
sieht man zwar die entstehende Binomialverteilung, aber die Kurve stimmt vorne und hinten nicht in der Darstellung
Und ich hnbe recht , wenn ich behaupte, daß die Kurven wenn sie skaliert sind vom optischen Eindruck her leichter untereinander zu vergleichen sind.

Die Aufgabe ist jedenfalls mit der erweiterten Ausgabefunktion gelöst und Du bist dran

Gruß, MarsStein
Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca
private Nachricht | Beiträge des Benutzers
talla
myCSharp.de - Experte

Avatar #avatar-3214.jpg


Dabei seit:
Beiträge: 7290
Herkunft: Esslingen

beantworten | zitieren | melden

Okay,

ich hab ne kleine Implementierungsaufgabe bei der es mehr um Wissen geht, als irgend einen Standardalgorithmus zu implementieren.

Gegeben ist ein Stück Code names Add welcher eine Addition von 4 Werten übernehmen soll. Er soll dabei folgendermaßen aufgerufen werden können:


            var erg = Add(1, 2, 3, 4);
            var erg2 = Add.SomethingNice()(1)(2)(3)(4);
In beiden Variablen, erg und erg2 soll als Ergebnis die Summe der Argumente, also 10, stehen.

Nun die Frage: Wie müsste Add aussehen und wie SomethingNice? Wie nennt man das, was da passiert. Ist es vielleicht gar nicht möglich in C# sowas zu schreiben?

EDIT: Kleine Ergänzung (die im Prinzip auch ein, gar nicht mal so unbedeutender, Tipp ist):
Sowas soll auch möglich sein:


            var tmp = Add.SomethingNice()(1)(3);
            var erg3 = tmp(4)(2);
Ergebniss ist natürlich wieder die Summe der Argumente, also 10.
Baka wa shinanakya naoranai.

Mein XING Profil.
private Nachricht | Beiträge des Benutzers
Corpsegrinder
myCSharp.de - Member



Dabei seit:
Beiträge: 416

beantworten | zitieren | melden

Ich gehe zwar davon aus, dass du eigentlich eine Lösung in F# haben wolltest, da es aber ja auch Scala für die .Net Plattform gibt hab ich es mal in Scala gemacht:

object Main {

  /**
   * @param args the command line arguments
   */
  def main(args: Array[String]): Unit = {
    println(Add(1,2,3,4))
    val add5 = Add.somethingNice(2)(3) _
    println(add5(2)(3))
  }

}

object Add {
  def apply(a: Int, b: Int, c: Int, d: Int) = somethingNice(a)(b)(c)(d)
  def somethingNice(a: Int)(b: Int)(c: Int)(d: Int) = a + b + c + d
}
private Nachricht | Beiträge des Benutzers
talla
myCSharp.de - Experte

Avatar #avatar-3214.jpg


Dabei seit:
Beiträge: 7290
Herkunft: Esslingen

beantworten | zitieren | melden

Zitat von Corpsegrinder
Ich gehe zwar davon aus, dass du eigentlich eine Lösung in F# haben wolltest

Dann hätte ich was gesagt. Ich dachte die Frage danach, ob es in C# geht, deutet darauf hin, dass ich natürlich eine Lösung in C# möchte :) Daher kann ich deine Lösung so nicht gelten lassen (ich kann praktisch kein Scala, aber soweit ich deinen Code verstehe macht er schon prinzipiell das wonach ich gefragt habe, halt auf die Scala Art)

EDIT: Durch die Antwort ist ja praktisch schon verraten das es natürlich in C# geht - ich hätte neben der Lösung aber auch noch den Namen der Technik ( aber bitte beides zusammen, nur die Nennung des Namens würde die Lösung dann durch suchen im Inet trivial machen)
Baka wa shinanakya naoranai.

Mein XING Profil.
private Nachricht | Beiträge des Benutzers