Vektorning ichki qismidagi satrlarni raqamlash

Quyidagi mag'lubiyatga e'tibor bering:

(def text "this is the first sentence . And this is the second sentence")

Matnda " bu " kabi so'zlarni sonini sanashni istadim. So'zning har bir paydo bo'lishidan keyin hisobni qo'shib qo'ying. Shunga o'xshash:

["this: 1", "is" "the" "first" "sentence" "." "and" "this: 2" ...]

Birinchi qadam sifatida men simni belgilab qo'ydim:

 (def words (split text #" "))

Keyin matnda " ushbu " sonini olish uchun yordamchi funksiya yaratdim:

 (defn count-this [x] (count(re-seq #"this" text)))

Va nihoyat, hisob-kitob natijasini ushbu funksiyadan foydalanib ishlatishga harakat qildim:

(for [x words]
(if (= x "this")
(str "this: "(apply str (take (count-this)(iterate inc 0))))
x))

Men mana bu narsa:

("this: 01" "is" "the" "first" "sentence" "." "And" "this: 01" "is" ...)
1
chunki hech qanday javob clojure.core/frequencies dan foydalanmaydi - bu erda doc
qo'shib qo'ydi muallif birdspider, manba

5 javoblar

Bunga vektor orqali o'tish orqali hisoblagichni yuborish uchun kamaytirish yordamida juda qisqacha erishish mumkin. kerak bo'lganda yangi satrlarni yaratish:

(def text "this is the first sentence. And this is the second sentence.")

(defn notate-occurences [word string]
  (->
    (reduce 
        (fn [[count string'] member] 
            (if (= member word) 
              (let [count' (inc count)]
                [count' (conj string' (str member ": " count'))])
              [count (conj string' member)]))
          [0 []]
          (clojure.string/split string #" "))
    second))

(notate-occurences "this" text) 
;; ["this: 1" "is" "the" "first" "sentence." "And" "this: 2" "is" "the" "second""sentence."]
1
qo'shib qo'ydi

Siz ketayotib, ba'zi davlatlarni saqlashingiz kerak. pastga , pastadir / recur va iterate hammasini amalga oshiring. iterate faqat bir davlatdan ikkinchisiga o'tadi. Bu erda o'tish vazifasi:

(defn transition [word]
  (fn [[[head & tail] counted out]]
    (let [[next-counted to-append] (if (= word head)
                                    [(inc counted) (str head ": " (inc counted))]
                                    [counted head])]
      [tail next-counted (conj out to-append)])))

Keyin hech qanday kiritish qolmaguncha bu funktsiyani ishlatish uchun iterate dan foydalanishingiz mumkin:

(let [in (s/split "this is the first sentence . And this is the second sentence" #" ")
      step (transition "this")]
    (->> (iterate step [in 0 []])
         (drop-while (fn [[[head & _] _ _]]
                       head))
         (map #(nth % 2))
         first))

;; => ["this: 1" "is" "the" "first" "sentence" "." "And" "this: 2" "is" "the" "second" "sentence"]
1
qo'shib qo'ydi
(defn split-by-word [word text]
    (remove empty?
        (flatten
            (map #(if (number? %) (str word ": " (+ 1 %)) (clojure.string/split (clojure.string/trim %) #" "))
                 (butlast (interleave
                      (clojure.string/split (str text " ") (java.util.regex.Pattern/compile (str "\\b" word "\\b")))
                      (range)))))))
1
qo'shib qo'ydi

Ushbu yondashuv bilan bog'liq muammo (amalda str (take (say-this) (iterate inc 0))) har doim bir xil narsalarni baholaydi.

Ayniqsa, pastadir shaklini ishlatmoqchi bo'lgan o'zgaruvchilar ustidan to'liq nazorat qilish uchun.

Masalan,

(defn add-indexes [word phrase]
  (let [words (str/split phrase #"\s+")]
    (loop [src words
           dest []
           counter 1]
      (if (seq src)
        (if (= word (first src))
          (recur (rest src) (conj dest (str word " " counter)) (inc counter))
          (recur (rest src) (conj dest (first src)) counter))
        dest))))

user=> (add-indexes "this" "this is the first sentence . And this is the second sentence")
["this 1" "is" "the" "first" "sentence" "." "And" "this 2" "is" "the" "second" "sentence"]

loop allows you to specify the value of every of the loop variables on each pass. So you can decide to change them or not according to your own logic.

Agar siz Java-ga tushib qolishni istasangiz va ehtimol aldash kabi his etilsa, bu ham ishlaydi.

(defn add-indexes2 [word phrase]
  (let [count (java.util.concurrent.atomic.AtomicInteger. 1)]
    (map #(if (= word %) (str % " " (.getAndIncrement count)) %)
         (str/split phrase #"\s+"))))

user=> (add-indexes2 "this" "this is the first sentence . And this is the second sentence")
("this 1" "is" "the" "first" "sentence" "." "And" "this 2" "is" "the" "second" "sentence")

O'zgaruvchan taymerni ishlatish befoyda bo'lmasligi mumkin, ammo boshqa tomondan, bu funktsiyaning kontekstidan hech qachon qochib ketmaydi, shuning uchun xatti-harakati tashqi kuchlar tomonidan o'zgartirilishi mumkin emas.

0
qo'shib qo'ydi
Umuman olganda, loop bu kabi narsalar uchun yaxshi tanlov deb o'ylayman, chunki iteratsiya o'tishlari bo'yicha qadriyatlarni boshqarish uchun ochiq qo'llab-quvvatlanmoqda va bu qisqartirishga urinishdan ko'ra biroz to'g'ir.
qo'shib qo'ydi muallif Bill, manba
Bu erda Java interopiga ehtiyoj yo'q, Clojure bu uchun atom ni ishlatadigan narsa.
qo'shib qo'ydi muallif Svante, manba
Javobingiz uchun tashakkur. Men sizning javobingizni tanladim, chunki men hozir Clojure (loops, recur) ni o'rganishda hozir edim.
qo'shib qo'ydi muallif omar, manba

Odatda, siz mavjud bo'lgan Clojure vazifalaridan juda murakkab tarzda sizning yechimingizni tuzishning oddiy usulini topishingiz mumkin.

Muammoingizga ikkita qisqa echim bor. Birinchidan, agar natija ketma-ketlikni talab qilmasa, lekin mag'lubiyatga o'zgartirilsa:

(require '(clojure.string))

(def text "this is the first sentence . And this is the second sentence")

(defn replace-token [ca token]
  (swap! ca inc)
  (str token ": " @ca))

(defn count-this [text]
  (let [counter     (atom 0)
        replacer-fn (partial replace-token counter)]
    (clojure.string/replace text #"this" replacer-fn)))

(count-this text)
; => "this: 1 is the first sentence . And this: 2 is the second sentence"

Yuqoridagi echim funktsiyani clojure.string/replace ga etkazish mumkinligi bilan bog'liq.

Ikkinchidan, natija ketma-ketlikni talab qilsangiz, tokenizingdan ba'zi bir xarajatlar mavjud:

(defn count-seq [text]
  (let [counter      (atom 0)
        replacer-fn  (partial replace-token counter)
        converter    (fn [tokens] (map #(if (not= % "this")
                                            % 
                                            (replacer-fn %))
                                       tokens))]
    (-> text
        (clojure.string/split #" ")
        (converter))))

(count-seq text)

; => ("this: 1" "is" "the" "first" "sentence" "." "And" "this: 2" "is" "the" "second" "sentence")

loop-recur naqshlari funktsional bo'lmagan tillardan kelgan Klojuriylarni boshlash uchun juda keng tarqalgan. Ko'pgina hollarda, xarita </​​code>, kamaytirish va do'stlar bilan funktsional ishlashni ishlatadigan tozalovchi va idrokiik echim mavjud.

Boshqa javoblar kabi, sizning dastlabki urinishlaringizdagi asosiy masala sizning hisoblagichingizning bog'lanishidir. Aslida, (iterate inc 0) hech narsa bilan bog'liq emas. Bog'langan atom taymer ko'lamini ko'rib chiqish uchun yuqoridagi misollarni ko'rib chiqing. Malumot sifatida bu erda yopilishidan foydalanishning namunasi , bu holda bu holda katta muvaffaqiyatga erishish mumkin!

Yuqoridagi misollar uchun dipnot sifatida: tozalovchi kod uchun count-seq va count-this funktsiyalarining umumiy qismlarini chiqarish va qayta ishlatish bilan umumiyroq hal qilish kerak. Bundan tashqari, mahalliy converter funktsiyasi count-seq dan chiqarilishi mumkin. replace-token all all tokens uchun allaqachon umumiydir, ammo hamma echim "bu" dan boshqa matnlar tashqari kengaytirilishi mumkinligini ko'rib chiqing. Ular o'quvchi uchun mashq qilib qoldirildi.

0
qo'shib qo'ydi