Foydalanuvchining yozuvidan raqamlar yig'indisi (Clojure)

Clojure bilan umumiy yangisidan savol. Vazifa juda oddiy, ammo buni qilishning eng yaxshi usulini topish qiyin kechadi - men foydalanuvchi (tabiiy foydalanuvchi sonini aniqlashi kerak) ro'yxatini berishi mumkin bo'lgan va kirishga ruxsat beradigan dasturni kiritish kerak Bu raqamlarning yig'indisi.

Ehtimol, bu allaqachon noto'g'ri.

(defn inputlist[naturallist]
  (println "Enter list of natural numbers:") 
  (let[naturallist(read-line)] ))
0

5 javoblar

Mana buni qilishning bir usuli:

> lein new app demo
> cd demo

project.clj va src/demo/core.clj tartibini o'zgartirish uchun quyidagilarga qarang:

> cat project.clj

(defproject demo "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.9.0"]
                 [org.clojure/tools.reader "1.1.3.1"] ]
  :main ^:skip-aot demo.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all}})

> cat src/demo/core.clj 

(ns demo.core
  (:require
    [clojure.tools.reader.edn :as edn]
    [clojure.string :as str]  ))

(defn -main []
  (println "enter numbers")
  (let [input-line (read-line)
        num-strs   (str/split input-line #"\s+")
        nums       (mapv edn/read-string num-strs)
        result     (apply + nums) ]
    (println "result=" result)))

Natijada

> lein run
enter numbers
1 2 3     <= you type this, then 

input-line   => "1 2 3"
num-strs     => ["1" "2" "3"]
nums         => [1 2 3]
result       => 6

Ba'zi boshlang'ich kitoblarni ko'rib chiqishni boshlashingiz mumkin:

4
qo'shib qo'ydi
Men misolni yangiladim. project.clj va src/demo/core.clj ni yarating va bu siz uchun ishlashi kerak.
qo'shib qo'ydi muallif Alan Thompson, manba
Salom! Ushbu kodni ishga tushirganimda firslty tupelo-ni qo'llashda xatolikka ega edi, endi qo'shilishimga qo'shilaman: CompilerException java.lang.RuntimeException: Belgini hal qila olmaydi: bu erda kontekstda defproject: (C: \ Users \ ... \ project.clj: 1: 1)
qo'shib qo'ydi muallif kjankausks, manba
Hozir yaxshi ishlaydi! Katta rahmat! Project.clj ning oxirgi 3 satridan boshqa hamma narsani olish kerak. Google, rahmat!
qo'shib qo'ydi muallif kjankausks, manba

Buni eng tezkor usul deb o'ylayman

#(apply + (map #(Integer/parseInt %) (re-seq #"\d+" (read-line))))

Bu anonim funksiyani belgilaydi:

  • (read-line) - raqamlar bo'lmagan belgilar bilan ajratilgan raqamlarni o'z ichiga olgan matnni o'qiydi. Shunday qilib siz "123 456 789" kabi narsalarni yozasiz.
  • (re-seq # "\ d +" ...) - ketma-ket raqamlar satrlarini qidirish uchun \ d + muntazam ifodasini ishlatadi. Keyingi ketma-ketlikdagi har bir satr ketma-ketlikga qo'shiladi va keyinchalik qaytariladi. Masalan, agar 123, 456, 789 kodini yozsangiz re-seq funktsiyasi '("123" "456" "789 ") .
  • (kod # (integer/parseInt%) ...) - re-seq tomonidan qaytarilgan ro'yxatdagi har bir element uchun # (Integer/parseInt%) chaqiruv, natijalarning boshqa ro'yxatini yaratish. Agar kirish '("123" "456" "789") bo'lsa, chiqish ' (123 456 789)
  • (apply + ...) - + funktsiyasini raqamlar ro'yxatiga kiritib, ularni jamlaydi va summasini qaytaradi.

Go'sht voila! Natijada, sonlar soni bilan ajratilgan, raqamlar bo'lmagan belgilar bilan ajratilgan bo'lsa, siz o'sha sonlarning yig'indisini qaytarib olasiz. Agar siz ozgina yoqimsiz bo'lishni istasangiz, kodni qaytadan ishlatishga yordam bering va umuman, buni biroz foydali qilingiz, uni alohida funksiyalarga aylantirishingiz mumkin:

(defn parse-string-list [s]
  (re-seq #"\d+" s))

(defn convert-seq-of-int-strings [ss]
  (map #(Integer/parseInt %) ss))

(defn sum-numbers-in-seq [ss]
  (apply + ss))

Buni Lisp-y usulida taklif qilish, xuddi shunga o'xshash ko'rinadi

(sum-numbers-in-seq (convert-seq-of-int-strings (parse-string-list (read-line))))

yoki ko'proq Clojure-y shaklida

(-> (read-line)
    (parse-string-list)
    (convert-seq-of-int-strings)
    (sum-numbers-in-seq))

Eng yaxshi omad.

1
qo'shib qo'ydi

Clojure-va StackOverflow-ga xush kelibsiz!

Buni qanday qilish kerak:

(defn input-numbers-and-sum []
  (print "Enter list of natural numbers: ")
  (flush)
  (->> (clojure.string/split (read-line) #"\s+")
       (map #(Integer/parseInt %))
       (reduce +)))

Bu qanday ishlaydi:

  • Calling print rather than println avoids printing a newline character at the end of the line. This way, the user's input will appear on the same line as your prompt.

  • Since there was no newline, you have to call flush to force the output buffer containing the prompt to be printed.

  • split splits what the user typed into a sequence of strings, divided where a regular expression matches. You have to say clojure.string/split rather than just split because split is not in Clojure's core library. clojure.string/ specifies the library. #"\s+" is a regular expression that matches any number of consecutive whitespace characters. So, if your user types "  6 82   -15   ", split will return ["6" "82" "-15"].

  • map calls the standard Java library function Integer.parseInt on each of those strings. Integer/parseInt is Clojure's Java interop syntax for calling a static method of a Java class. The #(...) is terse syntax that defines an anonymous function; the % is the argument passed to that function. So, given the sequence of strings above, this call to map will return a sequence of integers: [6 82 -15].

  • reduce calls the + function repeatedly on each element of the sequence of integers, passing the sum so far as an argument along with the next integer. map and reduce actually take three arguments; the next paragraph tells how the third paragraph gets filled in.

  • ->> is the "thread-last macro". It rewrites the code inside it, to pass the output of each expression but the last as the last argument of the following expression. The result is:

    (reduce + (map #(Integer/parseInt %) (clojure.string/split (read-line) #"\s+")))

    Most people find the version with ->> much easier to read.

That might seem like a lot to do something very simple, but it's actually bread and butter once you're used to Clojure. Clojure is designed to make things easy to combine; map, reduce, and ->> are especially useful tools for hooking other functions together.

Hujjatlarga havolalarni qo'shib qo'ydim. Ularga qarash kerak; Ko'pchilik odatda ulardan foydalanishning namunalarini o'z ichiga oladi.

Raqamlarni ajratishning boshqa usullari ham bor, albatta, ulardan ba'zilari bu savolga javoblarda ko'rsatiladi. Yuqorida yozganim, buni amalga oshirish uchun "odatiy" usul. Buni bilib oling va siz Clojure-da dasturlash uchun kundalik, bilish kerak bo'lgan ko'plab texnikani bilib olasiz.

1
qo'shib qo'ydi

Agar salbiy senaryolar (noto'g'ri kirish, sintaksis muammolari) haqida g'amxo'rlik qilmasangiz, eng tezkor yechim foydalanuvchining kirishini parenstga qo'yish uchun baholanadi:

(defn sum-ints []
  (let [input (read-line)
        ints (read-string (str "(" input ")"))]
    (reduce + 0 ints)))

Foydalanish:

user=> (sum-ints)
1 2 3 4 5
15

read-string funktsiyasi bu holda (1 2 3 4 5) matnli ifodani ko'rib chiqadi. Raqamlar sonlari raqamlarga aylantirilganda, natijalar faqat raqamlar ro'yxati bo'ladi.

0
qo'shib qo'ydi

Yep, readline - buni amalga oshirish uchun to'g'ri yo'l. Lekin readlines dan har bir element asosan java.lang.Character ning bir misolidir va siz summaning istagini berib, elementlarni to'plamasdan oldin ularni to'liq raqamga aylantirishni xohlaysiz ro'yxati.

(defn input-list
  []
  (print "Enter list of natural numbers") 
  (let [nums (read-line)] 
    (reduce + (map #(Integer/parseInt %) (clojure.string/split nums #"\s+")))

Bu buni amalga oshirishning eng odatiy usuli bo'lmasligi mumkin, lekin uni chimirishga qodir emas.

Bundan tashqari, iltimos, o'zgarmaydigan/funktsiya nomlaringizni tozalang.

Edit : (Integer/parseInt %) might cause an error if used directly since the input is an instance of characters, not string. So we can use clojure.string/split to convert user input to a sequence of strings, and use Integer/parseInt % for conversion.

Aslida, o'qiydigan yana bir versiya ip-birinchi makroslardan foydalanib yozilishi mumkin:

(defn input-list []
  (print "Enter list of natural numbers: ")
  (->> (clojure.string/split (read-line) #"\s+")
       (map #(Integer/parseInt %))
       (reduce +))) 

Buni amalga oshirish uchun yanada jozibali usul.

0
qo'shib qo'ydi
Yup, foydalanuvchi kiritish belgilar ketma-ketligidir va # (Integer/parseInt%) dan foydalanishdan oldin mag'lubiyatga aylantirilishi kerak. Uni aniqlang. Ko'rsatganingiz uchun tashakkur. @kjankausks
qo'shib qo'ydi muallif namc, manba
Xatolik bor. Konversiya bilan bog'liq ba'zi muammolar bormi? : ClassCastException java.lang.Character java.lang.String-ga uzatilishi mumkin emas
qo'shib qo'ydi muallif kjankausks, manba
Endi u ishlaydi! Bundan tashqari tushunish oson, rahmat, @namc!
qo'shib qo'ydi muallif kjankausks, manba