Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C#: Pitkän numeron pilkuttaminen

Sivun loppuun

E1ss [02.06.2017 18:11:14]

#

Ideana on että koodiini tulee pitkä numero esim 20000 tai vain 200 ja minun pitäisi tehdä koodissa siten että se pilkuttaisi numeron string muotoon. Esim 2000 -> 2,000 ja 10 -> 10. Kuinka tämä olisi mahdollista. Vastauksen voi lähettää millä tahansa koodilla mutta tässä on kyse c# ja unity.

Metabolix [02.06.2017 18:38:13]

#

Jos haluat muotoilla luvun oikein, käytä ToString-metodia.

int luku = 12345;
string teksti = luku.ToString("N0");

Esimerkiksi suomen kielessä lukuun ei kuulu pilkkuja muualle kuin kokonais- ja desimaaliosan väliin.

E1ss [03.06.2017 15:48:36]

#

Kiitos.

E1ss [19.06.2017 15:15:42]

#

Miten saan pilkutetun numeron muutettua takaisin normaaliksi luvuksi?

Jaska [19.06.2017 20:44:15]

#

Ei ole yksikäsitteistä tapaa. Ainoa pilkku voi olla desimaali- tai tuhaterotin. Onko vaikkapa 2,017 kuluva vuosi vai vähän suurempi arvo kuin 2? Mutta jos tiedät, että luvun on oltava kokonaisluku, niin tämän pitäisi toimia:

int num;
if (int.TryParse(toParse, NumberStyles.AllowThousands,
                 CultureInfo.InvariantCulture, out num))
{
    // Nyt num on kokonaisluku.
}

Napattu osoitteesta https://stackoverflow.com/questions/1824326/convert-toint32-a-string-with-commas

Metabolix [19.06.2017 23:47:37]

#

Yleensä olet tehnyt jotain väärin, jos lukuja pitää muuttaa tekstiksi ja ”takaisin”. Säilytä luvut lukuina joka paikassa, ja muuta niitä tekstiksi vain silloin, kun niitä pitää näyttää käyttäjälle. Säilytä silloinkin alkuperäinen luku normaalissa muodossa. Silloin ei tarvitse muuttaa yhtään lukua ”takaisin”.

Tietenkin joskus pitää lukea käyttäjän syötettä, ja silloin Jaskan selittämä tapa (tai vastaava) voi toimia, tai sitten voi yksinkertaisesti toivoa, että ainoa luvussa oleva piste tai pilkku olisi desimaalierotin.

E1ss [20.06.2017 07:42:46]

#

Joo huomasin että saan saman luvun ilman pilkkuja yhtä toista kautta. Tämä voisi vain hieman selkeyttää koodiani jos saisin pilkullisen numeron takaisin.

jalski [23.06.2017 10:06:37]

#

Vanhemmat ohjelmointikielet kuten Cobol ja PL/I ratkaisivat ongelman elegantisti PICTURE:n avulla. Näiden avulla pystyy jopa suoraan laskemaan, mikä tosin suuressa mittakaavassa ei suorituskyvyn kannalta välttämättä ole suositeltavaa (toistuva merkkijono - numero muunnos).

Alla PL/I esimerkki, mikä lukee luvun syötteenä PICTURE:en, sijoittaa sen fixed decimal luku muuttujaan ja tulostaa molemmat ruudulle.

test: proc options(main);

  dcl num fixed dec(9,2);
  dcl res pic'Z,ZZZ,ZZZV.99';

  put list('Anna luku:');
  get edit(res) (A(9));

  num = res;

  put skip list(num, res);

end test;

groovyb [23.06.2017 14:26:34]

#

No eipä tuo jalski mikään helpompi tapa ole.
Tässä lyhyt pätkä muunnoksesta formatoiduksi merkkijonoksi ja takaisin luvuksi C#:lla

int Luku = 4000245;
string LukuMerkkijonona = string.Format("{0:N0}", Luku);
//Koska kyseessä on kokonaisluku, NumberStyles.Number trimmaa pois kaikki muut paitsi 0-9.
int LukuTakaisin = int.Parse(LukuMerkkijonona, NumberStyles.Number);
//Vastaava liukuluvun kanssa
float Luku = 4000.23F;
string LukuMerkkijonona = string.Format("{0:N}", Luku);
float LukuTakaisin = float.Parse(LukuMerkkijonona, NumberStyles.Any);

Se, että kannattaako liukulukua käyttää enää merkkijonosta parsimisen jälkeen (alkuperäisen luvun tarkkuudesta ja formatoinnista riippuen), onkin sitten asia erikseen. Kuten Metabolix mainitsikin, lukuja ainoastaan NÄYTETÄÄN formatoituna. niitä käytetään kuitenkin alkuperäisen arvonsa mukaisesti.

jalski [23.06.2017 22:10:57]

#

groovyb kirjoitti:

No eipä tuo jalski mikään helpompi tapa ole.
Tässä lyhyt pätkä muunnoksesta formatoiduksi merkkijonoksi ja takaisin luvuksi C#:lla

Onhan se helpompi, kun ei tarvitse muistaa metodien nimiä ja parametrejä vaan voi suoraan sijoittaa lukumuuttujaan. Tehokkaampikin se varmasti desimaaliluvuilla laskettaessa on koska picturessa on kaikki tarvittava tieto nopeaa muunnosta varten.

Bonuksena voin myös laskea formatoiduilla merkkijonoilla suoraan:

dcl luku1 pic'Z,ZZZ,ZZZV.99' init('1225678.95');
dcl luku2 pic'Z,ZZZ,ZZZV.99' init('2145678.10');
dcl luku3 pic'Z,ZZZ,ZZZV.99' init((luku1+luku2));

groovyb [26.06.2017 16:07:41]

#

Huono argumentti, omassa esimerkissäsi pitää myös muistaa asioita. dc1, pic, init jne. olio-ohjelmoinnissa metodit (kuten itsekin käytät, esim tuo init tai pic:n parametriksi antamasi formaatti) sekä oliot ovat osa syntaksia. kun olio-ohjelmointia opetellaan, opetellaan myös peruskirjastot joita hyödynnetään. Se on sama asia kuin esimerkissäsi pic:n opettelu. Ja yhtäläin voi muissakin kielissä laskea ja näyttää samoilla muuttujilla, se on itsestä kiinni. Se että kannattaako formatuilla arvoilla tehdä laskutoimenpiteitä, on eri asia.

jalski [26.06.2017 19:39:18]

#

groovyb kirjoitti:

Huono argumentti, omassa esimerkissäsi pitää myös muistaa asioita. dc1, pic, init jne. olio-ohjelmoinnissa metodit (kuten itsekin käytät, esim tuo init tai pic:n parametriksi antamasi formaatti) sekä oliot ovat osa syntaksia. kun olio-ohjelmointia opetellaan, opetellaan myös peruskirjastot joita hyödynnetään. Se on sama asia kuin esimerkissäsi pic:n opettelu. Ja yhtäläin voi muissakin kielissä laskea ja näyttää samoilla muuttujilla, se on itsestä kiinni.

Nuo omassa esimerkissäni muistettavat asiat ovat siis ohjelmointikielen perusrakenteita:

dcl = declare
pic = picture
init = initialize

C#:llä joudut opettelemaan vastaavat asiat + olio-ohjelmointiin kuuluvat dokumentaation lukemista tai IDE:n intellisense ominaisuuden hyödyntämistä vaativat asiat.

Format ja parse metodit vaativat varmasti dokumentaation lukemista, jos niitä ei ole aiemmin käyttänyt. Picture:a taas osaa tulkita lähes jokainen sen ensikertaa kohtaava suoraan.

Olio-ohjelmointi toimii varmasti hyvin ja selkeyttää erilaisten isompien kokonaisuuksien koodaamista, mutta mielestäni ohjelmointikielen kaikkea perustoiminnallisuutta ei pitäisi piilottaa luokkiin.

LINQ tai luokat eivät auta edes niinkään yksinkertaisessa tehtävässä, kun pitäisi tulostaa paikallaan rotatoitu merkkijono varaamatta uutta merkkijonoa:

test: proc options(main);

  dcl msg1(29) char(1);
  dcl msg2(29) defined msg1(lbound(msg1,1)+mod(1sub-shift-lbound(msg1,1),hbound(msg1,1)-lbound(msg1,1)+1)) char(1);
  dcl shift fixed bin(31);

  string(msg1) = '*** PL1 is better than C# ***';

  do shift = 0 to 29;
    put edit((msg2(i) do i = 1 to 29)) (a(1)) skip;
  end;

end test;

Ohjelman tulostus:

*** PL1 is better than C# ***
**** PL1 is better than C# **
***** PL1 is better than C# *
****** PL1 is better than C#
 ****** PL1 is better than C#
# ****** PL1 is better than C
C# ****** PL1 is better than
 C# ****** PL1 is better than
n C# ****** PL1 is better tha
an C# ****** PL1 is better th
han C# ****** PL1 is better t
than C# ****** PL1 is better
 than C# ****** PL1 is better
r than C# ****** PL1 is bette
er than C# ****** PL1 is bett
ter than C# ****** PL1 is bet
tter than C# ****** PL1 is be
etter than C# ****** PL1 is b
better than C# ****** PL1 is
 better than C# ****** PL1 is
s better than C# ****** PL1 i
is better than C# ****** PL1
 is better than C# ****** PL1
1 is better than C# ****** PL
L1 is better than C# ****** P
PL1 is better than C# ******
 PL1 is better than C# ******
* PL1 is better than C# *****
** PL1 is better than C# ****
*** PL1 is better than C# ***

fergusq [26.06.2017 21:33:15]

#

jalski kirjoitti:

LINQ tai luokat eivät auta edes niinkään yksinkertaisessa tehtävässä, kun pitäisi tulostaa paikallaan rotatoitu merkkijono varaamatta uutta merkkijonoa:

Alla on vastaava ohjelma sekä perinteisen imperatiivisesti sekä LINQ-metodeita käyttäen. Enpä sanoisi niiden olevan millään lailla epäselvempiä kuin sinun koodisi, pikemminkin päin vastoin.

string msg1 = "*** C# on parempi kuin PL1 ***";

for (int i = 0; i < msg1.Length; i++) {
    for (int j = 0; j < msg1.Length; j++)
        Console.Write(msg1[(msg1.Length+j-i)%msg1.Length]);
    Console.WriteLine();
}

Console.Write(
    String.Join("\n",
                from i in Enumerable.Range(0, msg1.Length)
                select String.Concat(msg1.Skip(msg1.Length-i).Concat(msg1.Take(msg1.Length-i))))
);

jalski [27.06.2017 07:26:34]

#

fergusq kirjoitti:

Enpä sanoisi niiden olevan millään lailla epäselvempiä kuin sinun koodisi, pikemminkin päin vastoin.

Omassa esimerkissäni vain määrittely on monimutkaisemman näköinen, mutta koodi on yksinkertaisempi ja kaikki laskeminen jää kääntäjälle.

voin tehdä helposti esimerkiksi myös näin:

dcl diag(21) float bin(53) init(4, 2, 7, 9, 2, 4, 12, 36, 11, 90, 50, 8, 3, 34, 67, 3, 19, 21, 33, 73, 0);
dcl diagmat(20,20) float bin(53) defined diag(1sub*(1sub=2sub)+(1sub^=2sub)*hbound(diag));

Eli 20x20 lävistäjä matriisista tallennan vain lävistäjän ja yhden nolla-alkion. Voin silti käsitellä sitä kokonaisena M(n,n) muotoisena matriisina. Toisin sanoen 400 alkion sijaan tallennan vain 21 alkiota.

Sudokuja taas on helppo käsitellä näin:

define alias bits bit(9) aligned;
dcl total(81) type bits;
dcl matrix(9, 9) type bits based(p);
dcl p pointer;
dcl box(9, 3, 3) type bits defined (total(trunc((1sub-1)/3) * 27 +
    mod(1sub-1, 3) * 3 + (2sub-1) * 9 + 3sub));

dcl posbit(0:9) type bits
    init('000000000'b, '100000000'b, '010000000'b, '001000000'b,
         '000100000'b, '000010000'b, '000001000'b, '000000100'b,
         '000000010'b, '000000001'b);

dcl solutions(81) type bits controlled;

Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta