Προς το περιεχόμενο

Γενικό thread αποριών για τη C#.


Alithinos

Προτεινόμενες αναρτήσεις

  • Απαντ. 505
  • Δημ.
  • Τελ. απάντηση

Συχνή συμμετοχή στο θέμα

Συχνή συμμετοχή στο θέμα

Δημοσιευμένες Εικόνες

@defacer:

 

Woah! that escalated quickly.

Αν τα εξωτερικά {} οριοθετούν ολόκληρο το πίνακα, και τα εσωτερικά σειρές, τα μεσαία τι σημαίνουν ?

 

 

edit: nevermind, το ανακάλυψα!

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

[Α][β][γ][δ] α{ β{ γ{ δ{ }}} κλπ

 

Αυτη ειναι η λογικη. Και ειναι διαστασεις, οχι σειρες. Εξαλλου αυτος και ο σκοπος υπαρξης τους.

Ναι αλλά άμα πάω να προσθέσω επιπλέον άγκιστρα για να ενθυλακώσω τη μια διάσταση μέσα στην άλλη παίρνω:

 

Error 6 Array initializers can only be used in a variable or field initializer. Try using a new expression instead.

 

edit: άκυρο, είχα ξεχάσει ένα κόμμα.  :P

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Ρε μεγάλε Τρεις διαστάσεις λες,,,και δίνεις 5 νούμερα;

 

Προφανώς και τροποποίησα το παράδειγμα που μου έδωσε ο defacer ώστε να δημιουργήσω περισσότερες διαστάσεις, ώστε να βρω τον γενικότερο τύπο προσθήκης επιπλέον διάστασης... -_-

 

Γιατί στο ίδιο ακριβώς μήνυμα έγραψα πως δεν κατάλαβα τι ακριβώς συμβολίζουν τα ενδιάμεσα άγκιστρα.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Αν έχουμε έναν 2Χ2 και αποφασίσαμε να τον φτιάξουμε 3Χ2Χ2 πρέπει να βάλουμε 2Χ2, μετά 2Χ2 μετά 2Χ2,,άρα να πως βγήκε το 3άρι,

 

Αν έχουμε 2 στοιχεία απλά βάζουμε το δεύτερο μετά το πρώτο.

Αν έχουμε 2Χ2 κάνουμε το παραπάνω 2 φορές...

Κάθε φορά η επόμενη διάσταση μας λέει πόσες φορές θα "αυγατίσουν" τα προηγούμενα.

(το θέμα είναι οτι η "επόμενη διάσταση" είναι η πρώτη αριστερά στη C και άλλες παρόμοιες. Στη Μ2000 η πρώτη είναι η αριστερή, έτσι ώστε να αυξάνουμε την τελευταία, την δεξιά, αν θέλουμε π.χ. σε δυο διαστάσεις να προσθέσουμε γραμμές)

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Ναι αλλά άμα πάω να προσθέσω επιπλέον άγκιστρα για να ενθυλακώσω τη μια διάσταση μέσα στην άλλη παίρνω:

Δώσε και τον κώδικα εκτός από το error. Προφανώς κάτι κάνεις λάθος, αν δε δούμε κώδικα πώς θα καταλάβουμε;

 

Έχεις το σωστό type για τον πίνακα; string[,] = 2δ, string[,,] = 3δ, κλπ.

  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Όχι εντάξει βρήκα τι παίζει με τα 'μεσαία' άγκιστρα.Είναι όπως εξήγησε το  παπί.

Απλά τη πρώτη φορά που το δοκίμασα ξέχασα ένα κόμμα...  :P

 

Να πχ 4 διαστάσεις:

var FourD = new[,,,]
{
   {
      {
          { "a", "b", "c" },
          { "d", "e", "f" },
      },
      {
          { "g", "h", "i" },
          { "j", "k", "l" },
      },

   }, //Το κόμμα σε αυτή τη σειρά έλειπε τη πρώτη φορά που το δοκίμασα. 
   {
       {
          { "m", "n", "o" },
          { "p", "q", "r" },
       },
       {
          { "s", "t", "w" },
          { "x", "y", "z" },
       },
   }


};

Console.WriteLine(FourD[0,0,0,1]);
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

  • 2 εβδομάδες αργότερα...

Διάβασα για την αναδρομή προχθές.

Κατάλαβα τι κάνει, και έλυσα 3 ασκήσεις.

 

Μια που βρίσκει το factorial, μια που βρίσκει το αποτέλεσμα ενός αριθμού υψωμένου σε μια δύναμη, και μια που τυπώνει τα γράμματα της αλφαβήτου.

 

Ωστόσο δε βρίσκω το λόγο του γιατί να χρησιμοποιήσω αναδρομή και όχι ένα loop.

Καταρχάς πήρε το μάτι μου ότι η αναδρομή είναι πιο 'βαριά' από ότι μια λούπα. 

Και δεύτερον, όλοι φαίνεται να λένε πως ο λόγος για να χρησιμοποιήσεις αναδρομή, είναι επειδή έτσι κάποια προβλήματα λύνονται με τρόπο που φαίνεται πιο απλός και ευανάγνωστος στον προγραμματιστή.

 

Και εκεί είναι το πρόβλημα μου. Εμένα δε μου φαίνεται πιο απλός ο τρόπος επίτευξης με αναδρομή αντί για βρόχο.

Δηλαδή αυτο:

static void ShowAlphabetLoop()
        {
            for (char some = 'a'; some <= 'z'; some++)
            {
                Console.WriteLine(some);
            }
        }

μου φαίνεται αρκετά πιο απλό από αυτό:

static char ShowAlphabet(char aChar)
        {
            Console.WriteLine(aChar);
            aChar++;

            if (aChar == 'z')
            {
                Console.WriteLine('z');
                return aChar;
            }
            else
            {
                return ShowAlphabet(aChar);
            }
        }

στο οποίο θα έπρεπε να εισάγω όρισμα στη κλήση της μεθόδου.

 

Ίσως είναι ότι μέχρι τώρα χρησιμοποιούσα μόνο βρόχους και έτσι τους έχω συνηθίσει και έχω οικειότητα με αυτούς, και για αυτό μου φαίνεται πιο απλή η χρήση τους ? Ή μπορεί να είναι μήπως το είδος των προβλημάτων που μέχρι στιγμής είχα να αντιμετωπίσω, που εκφράζονται πιο εύκολα μέσω βρόχου ?

 

Πάντως η μέθοδος με τη λούπα, εκτός του ότι θα είναι πιο ελαφριά, καταφέρνει το ίδιο και με λιγότερες γραμμές κώδικα, μιας και η δήλωση της for επί της ουσίας συμπεριλαμβάνει τα απαραίτητα στοιχεία (μεταβλητή,συνθήκη,αύξηση μεταβλητής) τα οποία στη περίπτωση της αναδρομικής μεθόδου θα έπρεπε να τα φτιάξω το καθένα ξεχωριστά, και μου δίνεται έτσι η εντύπωση πως με την αναδρομή προσπαθώ να ανακαλύψω ξανά το τροχό...

 

Και αυτό δεν είναι αντιδεοντολογικό στις αρχές του Αντικειμενοστραφούς Προγραμματισμού, ο οποίος μας καλεί να κάνουμε επαναχρησιμοποίηση κώδικα, και να κρατάμε τις λεπτομέρειες 'κρυφές', προσθέτοντας επίπεδα 'αφηρημάδας' ?

Η χρήση μιας for στη συγκεκριμένη περίπτωση αντί αναδρομής καταφέρνει ακριβώς αυτό, σε λιγότερο χώρο, με τη χρήση λιγότερων πατημάτων πλήκτρων, καταφέρνει το ίδιο αποτέλεσμα, και έτσι όχι μόνο γράφεται πιο γρήγορα γλιτώνοντας μας χρόνο, αλλά είναι και πιο ευανάγνωστη, ακριβώς γιατί έχει λιγότερες σειρές, και όλα τα απαραίτητα για να καταλάβεις πόσες φορές θα γίνει η εκτέλεση είναι συμμαζεμένα σε μια σειρά. 

 

Άρα... γιατί να χρησιμοποιήσω αναδρομή αντί βρόχου ?

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Άρα... γιατί να χρησιμοποιήσω αναδρομή αντί βρόχου ?

 

Ενα κλασικο παράδειγμα traverse στα δυαδικά δεντρα.

public void Traverse(Node root)
{
  if(root != null)
  {
    Traverse(root.Left);
    Traverse(root.Right);
    print(root.Data);
  }
}

Ο μη-αναδρομικος τρόπος ειναι πιο περιπλοκος

http://stackoverflow.com/a/5496559/1750895

  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Alithinos, on 14 Apr 2016 - 06:21 AM, said:

 

Άρα... γιατί να χρησιμοποιήσω αναδρομή αντί βρόχου ?

 

Προσπάθησε να λύσεις επαναληπτικά ένα πρόβλημα που κλασσικά λύνεται με αναδρομή.

Π.χ. το Hanoi Tower.

Ή μια τρίλιζα.

Ή ένα backtracking πρόβλημα.

Ή....

 

Αμέσως θα διαπιστώσεις ότι η επαναληπτική λύση είναι πολύ πιο περίπλοκη και "αντι-οικονομική".

Ωστόσο, κι η σωστή εφαρμογή της αναδρομής σε πολλές περιπτώσεις δεν είναι τετριμμένη δουλειά, δυστυχώς.

Οι διαδικασίες των δέντρων είναι μια τέτοια περίπτωση.... 

 

-

  • Like 2
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Εκτός από το recursion υπάρχει και το reentrancy...Δείτε και αυτό! Π.χ. να έχουμε διαδοχική κλήση Α  -> Β->Α

κάτι σαν recursion αλλά να μεσολαβούν και άλλες συναρτήσεις!

  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Ωστόσο δε βρίσκω το λόγο του γιατί να χρησιμοποιήσω αναδρομή και όχι ένα loop.

Καταρχάς πήρε το μάτι μου ότι η αναδρομή είναι πιο 'βαριά' από ότι μια λούπα. 

Και δεύτερον, όλοι φαίνεται να λένε πως ο λόγος για να χρησιμοποιήσεις αναδρομή, είναι επειδή έτσι κάποια προβλήματα λύνονται με τρόπο που φαίνεται πιο απλός και ευανάγνωστος στον προγραμματιστή.

Το είπες μόνος σου, "κάποια" προβλήματα. Όχι όλα.

 

Η αναδρομή είναι όντως πιο βαριά στη γενική περίπτωση. Πώς προκύπτει αυτό; Απλά, συγκρίνεις το τι πρέπει να γίνει για να "πάρει μπρος" η επόμενη επανάληψη.

 

Στην περίπτωση του loop τυπικά (σε επίπεδο assembly) θα έχεις τρεις εντολές: μια increment, μια σύγκριση και μια conditional jump (πάει στην αρχή του loop ή απλά συνεχίζει παρακάτω ανάλογα το αποτέλεσμα της σύγκρισης).

 

Στην περίπτωση της αναδρομής ξεκινάς πρώτα απ' όλα με ένα function call, το οποίο σημαίνει ότι πρέπει να μπουν στο stack οι τιμές των κατάλληλων registers της CPU, στη συνέχεια αυτοί οι registers να πάρουν νέες τιμές, να μεγαλώσει το stack, ενδεχομένως να γίνει αρχικοποίηση local μεταβλητών στο καινούριο stack frame, μετά ένα jump στην αρχή του κώδικα της συνάρτησης, κι έχει ο θεός. Αυτό κοστίζει όχι μόνο σε χρόνο αλλά και σε χώρο στο stack -- εξ ου και αν βάλεις μια συνάρτηση που καλεί συνέχεια τον εαυτό της, σύντομα τελειώνει ο διαθέσιμος χώρος για το stack και καταλήγεις στο γνωστό stack overflow:) 

 

Αυτό βέβαια γενικά. Ειδικά, μια συνάρτηση που είναι tail recursive μπορεί να μετατραπεί από τον compiler σε ακριβές ισοδύναμο ενός loop (θυμήσου, ο compiler μπορεί να κάνει "ό,τι του αρέσει" αρκεί το αποτέλεσμα όπως φαίνεται σε έναν εξωτερικό παρατηρητή που έχει σα μόνη αναφορά το εκάστοτε spec της γλώσσας να είναι ακριβώς το ίδιο που θα ήταν αν είχε κάνει "ακριβώς ο,τι του είπες"). Υπάρχουν γλώσσες όπου ο compiler τυπικά το κάνει επειδή μπορεί (C++), άλλες που δε μπαίνει στον κόπο αν και θα μπορούσε (C#), άλλες που το spec εγγυάται το tail recursion όταν είναι εφικτό (Scheme).

 

TL;DR: use the right tool for the job.

 

Ίσως είναι ότι μέχρι τώρα χρησιμοποιούσα μόνο βρόχους και έτσι τους έχω συνηθίσει και έχω οικειότητα με αυτούς, και για αυτό μου φαίνεται πιο απλή η χρήση τους ? Ή μπορεί να είναι μήπως το είδος των προβλημάτων που μέχρι στιγμής είχα να αντιμετωπίσω, που εκφράζονται πιο εύκολα μέσω βρόχου ?

 

Πάντως η μέθοδος με τη λούπα, εκτός του ότι θα είναι πιο ελαφριά, καταφέρνει το ίδιο και με λιγότερες γραμμές κώδικα, μιας και η δήλωση της for επί της ουσίας συμπεριλαμβάνει τα απαραίτητα στοιχεία (μεταβλητή,συνθήκη,αύξηση μεταβλητής) τα οποία στη περίπτωση της αναδρομικής μεθόδου θα έπρεπε να τα φτιάξω το καθένα ξεχωριστά, και μου δίνεται έτσι η εντύπωση πως με την αναδρομή προσπαθώ να ανακαλύψω ξανά το τροχό...

 

Και τα δύο, στην προκειμένη περίπτωση βέβαια αντικειμενικά μεγαλύτερο ρόλο παίζει το δεύτερο. The right tool for the job. 

 

Η μέθοδος με αναδρομή είναι για εξάσκηση, όπως και το να κάνεις πολλαπλασιασμούς manually.

 

Και αυτό δεν είναι αντιδεοντολογικό στις αρχές του Αντικειμενοστραφούς Προγραμματισμού, ο οποίος μας καλεί να κάνουμε επαναχρησιμοποίηση κώδικα, και να κρατάμε τις λεπτομέρειες 'κρυφές', προσθέτοντας επίπεδα 'αφηρημάδας' ?

Η χρήση μιας for στη συγκεκριμένη περίπτωση αντί αναδρομής καταφέρνει ακριβώς αυτό, σε λιγότερο χώρο, με τη χρήση λιγότερων πατημάτων πλήκτρων, καταφέρνει το ίδιο αποτέλεσμα, και έτσι όχι μόνο γράφεται πιο γρήγορα γλιτώνοντας μας χρόνο, αλλά είναι και πιο ευανάγνωστη, ακριβώς γιατί έχει λιγότερες σειρές, και όλα τα απαραίτητα για να καταλάβεις πόσες φορές θα γίνει η εκτέλεση είναι συμμαζεμένα σε μια σειρά. 

 

Άρα... γιατί να χρησιμοποιήσω αναδρομή αντί βρόχου ?

 

1. Δεν έχει καμία σχέση με την κουβέντα ο αντικειμενοστραφής, μη μπερδεύεις έννοιες.

2. Η επαναχρησιμοποίηση κώδικα είναι κάτι γενικά επιθυμητό. Επίσης δε σχετίζεται με την κουβέντα, ούτε και με το ΟΟ συγκεκριμένα.

 

Στη συγκεκριμένη περίπτωση γίνομαι προβλέψιμος, αλλά δεν υπάρχει απολύτως κανένας λόγος να χρησιμοποιήσεις αναδρομή στην πράξη. Το κάνεις για εξάσκηση. Και αν το σκεφτείς είναι προεξοφλημένο πως εφόσον αυτού του είδους η εξάσκηση για να γίνει σωστά πρέπει να κάνεις κάτι που ήδη ξέρεις και καταλαβαίνεις απλά με άλλο τρόπο, και αυτό που ήδη ξέρεις και καταλαβαίνεις γίνεται καλύτερα με επανάληψη αφού δεν έχεις διδαχτεί νωρίτερα αναδρομή (και άρα τα πράγματα που γίνονται καλύτερα μ' αυτή), προφανώς το τελικό αποτέλεσμα από πρακτικής άποψης είναι suboptimal.

 

Εκτός από το recursion υπάρχει και το reentrancy...Δείτε και αυτό! Π.χ. να έχουμε διαδοχική κλήση Α  -> Β->Α

κάτι σαν recursion αλλά να μεσολαβούν και άλλες συναρτήσεις!

 

Καλώς το παλικάρι που ως συνήθως δεν ξέρει ή δε μπορεί να εκφράσει τι είναι reentrancy.  :rolleyes:

 

Reentrancy δεν είναι κάτι που συμβαίνει. Είναι μια ιδιότητα που είτε έχει είτε δεν έχει κάποια συγκεκριμένη συνάρτηση.

  • Like 2
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Defacer...

Ας δεχτούμε για τη συζήτηση ότι είναι μια ιδιότητα, εγώ θα το έλεγα ένα χαρακτηριστικό όπως και η δυνατότητα αναδρομής είναι ένα χαρακτηριστικό. Και αυτό γιατί δεν είναι δεδομένο ότι κάθε συνάρτηση μπορεί να καλέσει τον εαυτό της. H Fortran 77 δεν έχει Recursion στις συναρτήσεις, γιατί κάνει ιςι μεταβλητές στατικές στο κώδικα, δεν τις περνάει στο stack.

Θέτεις το χαρακτηριστικό "κάτι που συμβαίνει"....Δηλαδή να το πούμε, κάτι που γίνεται, μια κλήση συνάρτησης. Πώς λέγεται όμως μια διαδοχική κλήση, του Α() πολλές φορές πριν το αρχικό Α() τερματίσει και αυτό γίνει από άλλες συναρτήσεις...π.χ. το Α() καλεί το Β() το Β() το Γ(), το Γ() το Α() και συνεχίζεται για καμιά τριανταριά κλήσεις;

Δεν λέγεται αναδρομή. Δεν καλεί η Α() την Α().

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα

  • Δημιουργία νέου...