तत्वों की निश्चित संख्या के साथ कई सूचियों में विभाजित सूची


119

अधिकांश एन आइटमों के साथ सूचियों में तत्वों की सूची को कैसे विभाजित करें?

पूर्व: 7 तत्वों के साथ एक सूची को देखते हुए, 4 के समूह बनाएं, अंतिम समूह को संभवतः कम तत्वों के साथ छोड़ दें।

split(List(1,2,3,4,5,6,"seven"),4)

=> List(List(1,2,3,4), List(5,6,"seven"))

जवाबों:


213

मुझे लगता है कि आप ढूंढ रहे हैं grouped। यह एक पुनरावृत्ति देता है, लेकिन आप परिणाम को सूची में बदल सकते हैं,

scala> List(1,2,3,4,5,6,"seven").grouped(4).toList
res0: List[List[Any]] = List(List(1, 2, 3, 4), List(5, 6, seven))

25
स्काला सूचियों में हर चीज के लिए कुछ न कुछ है।
J Atkin

मेरा एक अजीब सवाल है। उसी मामले के लिए यदि मैं डेटा को अनुक्रम में परिवर्तित करता हूं, तो मुझे एक स्ट्रीम ऑब्जेक्ट मिलता है। ऐसा क्यों है?
राकेश

3
@ रक्षा एक अलग प्रश्न की तरह लगता है। स्काला में एक रहस्यमय सूक्ति है जो एक डेटा संरचना चुनती है, और इसने आपके लिए एक स्ट्रीम चुनी। यदि आप एक सूची चाहते हैं, तो आपको एक सूची का अनुरोध करना चाहिए, लेकिन आप केवल सूक्ति के फैसले पर भरोसा कर सकते हैं।
आयन फ्रीमैन

12

स्लाइडिंग विधि का उपयोग करके कार्य करने का बहुत आसान तरीका है। यह इस तरह से काम करता है:

val numbers = List(1, 2, 3, 4, 5, 6 ,7)

कहते हैं कि आप सूची को आकार 3 की छोटी सूची में तोड़ना चाहते हैं।

numbers.sliding(3, 3).toList

तुम्हे दूंगा

List(List(1, 2, 3), List(4, 5, 6), List(7))

9

या यदि आप अपना खुद का बनाना चाहते हैं:

def split[A](xs: List[A], n: Int): List[List[A]] = {
  if (xs.size <= n) xs :: Nil
  else (xs take n) :: split(xs drop n, n)
}

उपयोग:

scala> split(List(1,2,3,4,5,6,"seven"), 4)
res15: List[List[Any]] = List(List(1, 2, 3, 4), List(5, 6, seven))

संपादित करें : 2 साल बाद इसकी समीक्षा करने के बाद, मैं इस कार्यान्वयन की सिफारिश नहीं करूंगा क्योंकि sizeO (n) है, और इसलिए यह विधि O (n ^ 2) है, जो बताती है कि अंतर्निहित सूची बड़ी सूचियों के लिए क्यों तेज हो जाती है, जैसा कि नीचे टिप्पणी में नोट किया गया है। आप निम्नानुसार कुशलतापूर्वक लागू कर सकते हैं:

def split[A](xs: List[A], n: Int): List[List[A]] =
  if (xs.isEmpty) Nil 
  else (xs take n) :: split(xs drop n, n)

या यहां तक ​​कि (थोड़ा) अधिक कुशलता से उपयोग splitAt:

def split[A](xs: List[A], n: Int): List[List[A]] =
  if (xs.isEmpty) Nil 
  else {
    val (ys, zs) = xs.splitAt(n)   
    ys :: split(zs, n)
  }

4
xs splitAt nसंयोजन का एक विकल्प है xs take nऔरxs drop n
Kipton Barros 6

1
यह स्टैक में विस्फोट करेगा, एक पुनरावर्ती कार्यान्वयन पर विचार करें
जेड वेस्ले-स्मिथ

@ किपटन, सच है, लेकिन आपको अस्थायी घाटी में परिणाम निकालने की आवश्यकता है, इसलिए यह एक विधि में कुछ पंक्तियों को जोड़ता है। मैंने एक त्वरित बेंचमार्क किया और यह 4% के आसपास औसतन प्रदर्शन में सुधार / सुधार के splitAtबजाय उपयोग करता है; दोनों की तुलना में 700-1000% तेज हैं ! takedrop.grouped(n).toList
लुइगी प्लिंज

@ लुइगी, वाह। grouped-toListइतना धीमा क्यों है इसके बारे में कोई विचार ? यह एक बग की तरह लगता है।
किप्टन बैरोस

@ जेड आप चरम मामलों में सही हैं, लेकिन आपका कार्यान्वयन इस बात पर निर्भर करता है कि आप इसके लिए क्या उपयोग कर रहे हैं। ओपी के उपयोग के मामले (यदि groupedमौजूद नहीं था :)), सादगी ओवरराइडिंग कारक है। मानक पुस्तकालय के लिए, स्थिरता और प्रदर्शन को शान से ट्रम्प करना चाहिए। लेकिन स्काला में प्रोग्रामिंग और सामान्य-पुनरावर्ती (पूंछ-पुनरावर्ती) कॉल के बजाय मानक पुस्तकालयों में दोनों उदाहरण बहुत हैं; यह एफपी टूलबॉक्स में एक मानक और महत्वपूर्ण हथियार है।
लुइगी प्लिंज

4

मैं विभाजन विधि का एक पूंछ पुनरावर्ती संस्करण जोड़ रहा हूं क्योंकि पूंछ-पुनरावृत्ति बनाम पुनरावृत्ति की कुछ चर्चा थी। संकलक को वास्तव में पुनरावर्ती नहीं होने की स्थिति में शिकायत करने के लिए मजबूर करने के लिए मैंने टेलरेक एनोटेशन का उपयोग किया है। टेल-रिकर्सन मेरा मानना ​​है कि हुड के नीचे एक लूप में बदल जाता है और इस तरह बड़ी सूची के लिए भी समस्या नहीं होगी क्योंकि स्टैक अनिश्चित काल तक नहीं बढ़ेगा।

import scala.annotation.tailrec


object ListSplitter {

  def split[A](xs: List[A], n: Int): List[List[A]] = {
    @tailrec
    def splitInner[A](res: List[List[A]], lst: List[A], n: Int) : List[List[A]] = {
      if(lst.isEmpty) res
      else {
        val headList: List[A] = lst.take(n)
        val tailList : List[A]= lst.drop(n)
        splitInner(headList :: res, tailList, n)
      }
    }

    splitInner(Nil, xs, n).reverse
  }

}

object ListSplitterTest extends App {
  val res = ListSplitter.split(List(1,2,3,4,5,6,7), 2)
  println(res)
}

1
कुछ स्पष्टीकरण जोड़कर इस उत्तर को बेहतर बनाया जा सकता था। यह देखते हुए कि स्वीकृत उत्तर ऐसा करने के लिए विहित, अभिप्रेत तरीका प्रतीत होता है, आपको यह बताना चाहिए कि कोई व्यक्ति इस उत्तर को क्यों पसंद करेगा।
जेफरी बोसबोम

0

मुझे लगता है कि यह ले / ड्रॉप के बजाय स्प्लिट ए का उपयोग करके कार्यान्वयन है

def split [X] (n:Int, xs:List[X]) : List[List[X]] =
    if (xs.size <= n) xs :: Nil
    else   (xs.splitAt(n)._1) :: split(n,xs.splitAt(n)._2)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.