/**Collection Operation Demo
 * 0)初始化:List、Set、Map
 * 1)遍历
 * 2)拷贝 深拷贝：List<T>
 * 3)转换（映射） map:List<T>->List<R>  associate:List<T>->Map(K,V)  joinToString:List<T>->String zip:List<T>->List(Pair(T,R))
 * 4)过滤：List<T>/Null、Pair(List<T>,List<T>)
 * 5)检索:T/Null、List<T>、List<List<T>>
 * 6)排序：Unit、List<T>
 * 7)聚合（统计）:Int/Double、T
 * 8)分组:Map(K,List<T>)
 * 9)写：添加、删除、更新
 * 10)+/-:可为不可变集合增减元素
 */
data class Shop(var name: String, var customers: List<Customer>)
data class Customer(val name: String, val city: City, val orders: List<Order>) {
    override fun toString() = "$name from ${city.name}"
}
data class Order(val products: List<XProduct>, val isDelivered: Boolean)
data class XProduct(val name: String, val price: Double) {
    override fun toString() = "'$name' for $price"
}
data class City(val name: String) {
    override fun toString() = name
}
val city1=City("Beijing")
val city2=City("Shanghai")
val products1= listOf(XProduct("phone",200.0) , XProduct("desk",300.0) , XProduct("tv",1200.0) ,XProduct("computer",2200.0) )
val products2= listOf(XProduct("phone",300.0) , XProduct("desk",200.0) , XProduct("tv",1100.0) ,XProduct("computer",3300.0) )
val orders1 = listOf(Order(products1,true),Order(products2,false))
val orders2 = listOf(Order(products1,false),Order(products2,false))
val customer1=Customer("zhangsan",city1,orders1)
val customer2=Customer("lisi",city2,orders2)
val shop=Shop("myShop",listOf(customer1,customer2))

@kotlin.ExperimentalStdlibApi
fun main() {
    contructors()
    iterators()
    copying()
    transformations()
    filtering()
    retrievingElement()
    retrievingCollectionParts()
    ordering()
    aggregate()
    grouping()
    writing()
    plusAndMinus()
}

@kotlin.ExperimentalStdlibApi
fun contructors(){
    println("-----------------------------Collection Constructor Demo------------------------------")
    //list
    println("-----------------list Constructor------------------")
    val arr = arrayOf("1","2",3,4,5)
    val list1 = listOf(1,2,"3",4,"5")                // 随意创建:[1, 2, 3, 4, 5]
    val list2 = listOf<String>("1","2","3","4","5")  // 确定元素的值类型:[1, 2, 3, 4, 5]
    val list3 = listOf(arr)                          //  [[Ljava.lang.Object;@58372a00]
    val list4 = listOfNotNull("Java", "Kotlin", null, "Go")   //[Java, Kotlin, Go]
    val list5 = buildList(list1.size + 2) {
        add('a')
        addAll(list1)
        add('b')
    }   // [a, 1, 2, 3, 4, 5, b]
    log("List",list1,list2,list3,list4,list5)

    val mutableList1 = mutableListOf(1,2,"3",4,"5")                // 随意创建:[1, 2, 3, 4, 5]
    val mutableList2 = mutableListOf<String>("1","2","3","4","5")  // 确定元素的值类型:[1, 2, 3, 4, 5]
    val mutableList3 = mutableListOf(arr)                          // 可传入一个数组：[[Ljava.lang.Object;@58372a00]
    val mutableList4 = arrayListOf("Java", "Kotlin", null, "Go")   //[Java, Kotlin, null, Go]
    log( "MutableList",mutableList1, mutableList2, mutableList3, mutableList4)
    //set
    println("-----------------Set Constructor------------------")
    val set1 = setOf(1,2,"3","4","2",1,2,3,4,5)  //集合元素按添加顺序排列：[1, 2, 3, 4, 2, 3, 4, 5]
    val set2= buildList(set1.size + 2) {
        add('a')
        addAll(set1)
        add('b')
    }  //[a, 1, 2, 3, 4, 2, 3, 4, 5, b]
    log("Set",set1,set2)
    val mutableSet1 = mutableSetOf(1,2,"3","4","2",1,2,3,4,5) //集合元素按添加顺序排列：[1, 2, 3, 4, 2, 3, 4, 5]
    val mutableSet2 =hashSetOf("java","kotlin","swift")  //不保证元素的顺序： [kotlin, java, swift]
    val mutableSet3 =linkedSetOf("java","kotlin","swift")  //集合元素按添加顺序排列： [java, kotlin, swift]
    val mutableSet4 =sortedSetOf("java","kotlin","swift")  //集合元素由小到大排列： [java, kotlin, swift]
    log("MutableSet",mutableSet1, mutableSet2, mutableSet3, mutableSet4)
    //map
    println("-----------------Map Constructor------------------")
    val map1 = mapOf("key1" to 2 , "key2" to 3)//按添加顺序排列：{key1=2, key2=3}
    val map2 = mapOf<Int,String>(1 to "value1" , 2 to "value2") // {1=value1, 2=value2}

    val map3 = buildMap<String, Int>(map1.size + 3) {
        put("a", 1)
        put("b", 0)
        putAll(map1)
        put("c", 4)
    }// {a=1, b=0, key1=2, key2=3, c=4}
    log("Map",map1,map2,map3)
    val mutableMap1 = mutableMapOf("key1" to 2 , "key2" to 3)//按添加顺序排列：{key1=2, key2=3}
    val mutableMap2 = hashMapOf("key1" to 2 , "key2" to 3)  //不保证排列顺序：{key1=2, key2=3}
    val mutableMap3= linkedMapOf("key1" to 2 , "key2" to 3 ) //按添加顺序排列：{key1=2, key2=3}
    val mutableMap4= sortedMapOf("Java" to 86, "Kotlin" to 92, "Go" to 78)   //按key由小到大排列：{Go=78, Java=86, Kotlin=92}
    log("MutableMap",mutableMap1, mutableMap2, mutableMap3, mutableMap4)
}
fun iterators() {
    println("-----------------------------Collection Iterators Demo------------------------------")
    val numbers = listOf("one", "two", "three", "four")
    val numbersIterator = numbers.iterator()
    print("iterator.next:")
    while (numbersIterator.hasNext()) {
        print(numbersIterator.next() + ",")
    }   //one,two,three,four,
    /*可选替代
    val numbersListIterator = numbers.listIterator()
    print("iterator.next:")
    while (numbersListIterator.hasNext()) {
        print(numbersListIterator.next() +  if(numbersListIterator.nextIndex()<=numbers.lastIndex)"," else "")
    }*/
    println()
    print("for in:")
    for (item in numbers) {
        print(item + if (numbers.indexOf(item) < numbers.lastIndex) "," else "")
    }  //one,two,three,four
    println()

    print("forEach:")
    numbers.forEach {
        print(it + ",")
    }   //one,two,three,four,
    /*可选替代
    numbers.forEachIndexed() {idx,element->
       print(element + if(idx<numbers.lastIndex)"," else "")
    }*/
    println()

    print("onEach:")
    numbers.onEach {
        print(it + ",")
    }    //one,two,three,four，
    println()

    print("forRange:")
    for (i in 0..numbers.lastIndex) print(numbers[i] + if (i < numbers.lastIndex) "," else "")   //one,two,three,four
    println()

    println("-----------------listIterator------------------")
    val listIterator = numbers.listIterator()
    println("Iterating forwards:")
    while (listIterator.hasNext()) {
        print("Index: ${listIterator.nextIndex()}")
        println(", value: ${listIterator.next()}")
    }//Index: 0, value: one
     //Index: 1, value: two
     //Index: 2, value: three
     //Index: 3, value: four

    println("Iterating backwards:")
    while (listIterator.hasPrevious()) {
        print("Index: ${listIterator.previousIndex()}")
        println(", value: ${listIterator.previous()}")
    } //Index: 3, value: four
      //Index: 2, value: three
      //Index: 1, value: two
      //Index: 0, value: one

    println("-----------------Mutable iterators------------------")
    val numbers1 = mutableListOf("one", "two", "three", "four")
    val mutableIterator = numbers1.iterator()
    mutableIterator.next()
    mutableIterator.remove()
    println("After removal: $numbers1")//[two, three, four]

    val mutableListIterator = numbers1.listIterator()
    mutableListIterator.next()
    mutableListIterator.add("five")
    mutableListIterator.next()
    mutableListIterator.set("six")
    println("After addition: $numbers1")// [two, five, six, four]
}

fun copying() {
    println("-----------------------------Collection Copying Demo------------------------------")
    println("-----------------List------------------")
    val sourceList = listOf(1, 2, 3)
    val copyList = sourceList.toMutableList()
    val readOnlyCopyList =copyList.toList()
    copyList.add(4)
    println("Source size: ${sourceList.size}")  //3
    println("Copy size: ${copyList.size}")      //4
    //readOnlyCopyList.add(4)             // compilation error
    println("Read-only copy size: ${readOnlyCopyList.size}") //3

    val copySet = copyList.toMutableSet()
    copySet.add(5)
    copySet.add(6)
    copyList.add(0)
    println("CopyList:$copyList")//[1, 2, 3, 4, 0]
    println("CopySet:$copySet")  //[1, 2, 3, 4, 5, 6]

    val referenceList1 = copyList
    referenceList1.add(7)
    println("Copy Source size: ${copyList.size}") //6
    println("referenceList size: ${referenceList1.size}")  //6

    val referenceList2: List<Int> = copyList
    //referenceList2.add(4)            //compilation error
    copyList.add(8)
    println("Copy Source : $copyList")        //[1, 2, 3, 4, 0, 7, 8]
    println("referenceList:$referenceList2")  //[1, 2, 3, 4, 0, 7, 8]

    println("-----------------Array------------------")
    val array1 = arrayOf("apples", "oranges", "limes")
    val arrayCopy = array1.copyOf()   //copyOf(size:Int)/copyOfRange(...)/copyInto(...)
    array1[0] = "pearls"
    println(array1.contentToString())     //[pearls, oranges, limes]
    println(arrayCopy.contentToString())  //[apples, oranges, limes]

    val array2 = intArrayOf(1, 2, 3)
    val arrayCopyPadded = array2.copyOf(5)
    val arrayCopyTruncated = array2.copyOf(2)
    array2[0] = 0
    println(array2.contentToString())             //[0, 2, 3]
    println(arrayCopyPadded.contentToString())    //[1, 2, 3, 0, 0]
    println(arrayCopyTruncated.contentToString()) //[1, 2]

}

fun transformations() {
    fun parseFullName(name: String): Pair<String, String> {
        val names = name.split(" ")
        val firstName = names[1]
        val lastName = names[0]
        return Pair(firstName, lastName)
    }

    println("-----------------------------Collection Transformations Demo------------------------------")
    //Mapping，将List<T>转List<R>
    println("-----------------Mapping------------------")
    val numbers = setOf(1, 2, 3)
    println(numbers.map { it * 3 })   //[3, 6, 9]
    println(numbers.mapIndexed { idx, value -> value * idx })   //[0, 2, 6]
    println(numbers.mapNotNull { if (it == 2) null else it * 3 })   //[3, 9]
    println(numbers.mapIndexedNotNull { idx, value -> if (idx == 0) null else value * idx })   //[2, 6]
    val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)
    println(numbersMap.mapKeys { it.key.toUpperCase() })   //{KEY1=1, KEY2=2, KEY3=3, KEY11=11}
    println(numbersMap.mapValues { it.value + it.key.length })   //{key1=5, key2=6, key3=7, key11=16}
    //Zipping
    println("-----------------Zipping------------------")
    val colors = listOf("red", "brown", "grey")
    val animals = listOf("fox", "bear", "wolf")
    println(colors zip animals)    //[(red, fox), (brown, bear), (grey, wolf)]
    val twoAnimals = listOf("fox", "bear")
    println(colors.zip(twoAnimals))     //[(red, fox), (brown, bear)]
    println(colors.zip(animals) { color, animal -> "The ${animal.capitalize()} is $color" })    //[The Fox is red, The Bear is brown, The Wolf is grey]
    val numberPairs = listOf("one" to 1, "two" to 2, "three" to 3, "four" to 4)
    println(numberPairs.unzip())    //([one, two, three, four], [1, 2, 3, 4])

    //Association
    println("-----------------Association------------------")
    val names = listOf("Alice Adams", "Brian Brown", "Clara Campbell")
    println(names.associate { name -> parseFullName(name).let { it.first to it.second } })  //{Adams=Alice, Brown=Brian, Campbell=Clara}

    val numbers1 = listOf("one", "two", "three", "four")
    println(numbers1.associateWith { it.length })   //{one=3, two=3, three=5, four=4}
    println(numbers1.associateBy { it.first().toUpperCase() })  //{O=one, T=three, F=four}
    println(numbers1.associateBy(keySelector = { it.first().toUpperCase() }, valueTransform = { it.length }))  //{O=3, T=5, F=4}
    //Flattening
    println("-----------------Flattening------------------")
    val numberSets = listOf(setOf(1, 2, 3), setOf(4, 5, 6), setOf(1, 2))
    println(numberSets.flatten())   //[1, 2, 3, 4, 5, 6, 1, 2]
    val containers = listOf(
        listOf("one", "two", "three"),
        listOf("four", "five", "six"),
        listOf("seven", "eight")
    )
    println(containers.flatMap{ it })  //[one, two, three, four, five, six, seven, eight]

    //flatmap 可以将一个List<List(T)>转为List<R>,其中R是T的一部分

    println("对象转换1:${orders1.flatMap(Order::products)}") //['phone' for 200.0, 'desk' for 300.0, 'tv' for 1200.0, 'computer' for 2200.0, 'phone' for 300.0, 'desk' for 200.0, 'tv' for 1100.0, 'computer' for 3300.0]
    println(shop.customers.flatMap {it.orders}.flatMap{it.products})  //'phone' for 200.0, 'desk' for 300.0, 'tv' for 1200.0, 'computer' for 2200.0, 'phone' for 300.0, 'desk' for 200.0, 'tv' for 1100.0, 'computer' for 3300.0, 'phone' for 200.0, 'desk' for 300.0, 'tv' for 1200.0, 'computer' for 2200.0, 'phone' for 300.0, 'desk' for 200.0, 'tv' for 1100.0, 'computer' for 3300.0]
    println("对象转换2:-------:${products1.map{it.price}}") //[200.0, 300.0, 1200.0, 2200.0]
    //Count the amount of times a product was ordered
    println(shop.customers.flatMap{it.getOrderedProducts()}.count { it == products1[1] })
    //Find the most expensive product among all the delivered products
    println(customer1.orders
                     .filter(Order::isDelivered)
                     .flatMap(Order::products)
                     .maxByOrNull (XProduct::price))

    //String representation
    println("-----------------String representation------------------")
    println(numbers1) //[one, two, three, four]
    println(numbers1.joinToString())  //one, two, three, four
    val listString = StringBuffer("The list of numbers: ")
    numbers1.joinTo(listString)
    println(listString)   // The list of numbers: one, two, three, four
    println(numbers1.joinToString(separator = " | ", prefix = "start: ", postfix = ": end"))  //start: one | two | three | four: end
    println(numbers1.joinToString { "Element: ${it.toUpperCase()}" })  //Element: ONE, Element: TWO, Element: THREE, Element: FOUR
    val numbers2 = (1..100).toList()
    println(numbers2.joinToString(limit = 10, truncated = "<...>"))    //1, 2, 3, 4, 5, 6, 7, 8, 9, 10, <...>
}

fun filtering() {
    println("-----------------------------Filtering Demo------------------------------")
    println("-----------------Filtering by predicate------------------")
    val numbers = listOf("one", "two", "three", "four")
    val longerThan3 = numbers.filter { it.length > 3 }
    println(longerThan3)   //[three, four]

    val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)
    val filteredMap = numbersMap.filter { (key, value) -> key.endsWith("1") && value > 10 }
    println(filteredMap)    //{key11=11}

    val filteredIdx = numbers.filterIndexed { index, s -> (index != 0) && (s.length < 5) }
    val filteredNot = numbers.filterNot { it.length <= 3 }

    println(filteredIdx)    //[two, four]
    println(filteredNot)    //[three, four]

    val numbers1 = listOf(null, 1, "two", 3.0, "four")
    println("All String elements in upper case:")
    numbers1.filterIsInstance<String>().forEach {
        println(it.toUpperCase())
    }//TWO
     //FOUR
    val numbers2 = listOf(null, "one", "two", null)
    numbers2.filterNotNull().forEach {
        println(it.length)   // length is unavailable for nullable Strings
    }//3
     //3

    //Partitioning
    println("-----------------Partitioning------------------")
    println(numbers)    //[one, two, three, four]
    val (match, rest) = numbers.partition { it.length > 3 }
    println(match)  //[three, four]
    println(rest)   //[one, two]

    println("-----------------Testing predicates------------------")
    val empty = emptyList<String>()
    println(numbers.any())  //true
    println(empty.any())    //false
    println(numbers.none()) //false
    println(empty.none())   //true

    println(numbers.any { it.endsWith("e") })   //true
    println(numbers.none { it.endsWith("a") })  //true
    println(numbers.all { it.endsWith("e") })   //false
    println(emptyList<Int>().all { it > 5 })          //true
}

fun retrievingElement() {
    println("------------------------------------Retrieving Single Elements Demo------------------------------------")
    //Retrieving by position
    println("-----------------Retrieving by position------------------")
    val numberList = listOf(1, 2, 3, 4, 5)
    println(numberList[3])      //4
    println(numberList.get(3))  //4

    val numbers = linkedSetOf("one", "two", "three", "four", "five")
    println(numbers.elementAt(3))   //four
    println(numbers.first())              //one
    println(numbers.last())               //five


    val numbersSortedSet = sortedSetOf("one", "two", "three", "four")
    println(numbersSortedSet.elementAt(0)) //four
    println(numbers.elementAtOrNull(5))    //null
    println(numbers.elementAtOrElse(5) { index -> "The value for index $index is undefined" })  //The value for index 5 is undefined

    //Retrieving by condition
    println("-----------------Retrieving by condition------------------")
    println(numbers.first { it.length > 3 })            //three
    println(numbers.last { it.startsWith("f") })  //five
    println(numbers.firstOrNull { it.length > 6 })      //null

    println(numbers.find { it.length > 3 })    //等价firstOrNull():three
    println(numbers.findLast { it.length > 3 })//等价lastOrNull():five

    //Random element
    println("-----------------Random element------------------")
    println(numbers.random())

    //binarySearch
    println("-----------------binarySearch------------------")
    val colors = listOf("Blue", "green", "ORANGE", "Red", "yellow")
    log("search",colors.binarySearch("RED", String.CASE_INSENSITIVE_ORDER)) // 3
    data class Box(val value: Int)
    val numbers1 = listOf(1, 3, 7, 10, 12)
    val boxes = numbers1.map { Box(it) }
    log("searchBy",boxes.binarySearchBy(10) { it.value }) // 3

    //Checking existence
    println("-----------------Checking existence------------------")
    println(numbers.contains("four"))       //true
    println("zero" in numbers)              //false

    println(numbers.containsAll(listOf("four", "two")))     //true
    println(numbers.containsAll(listOf("one", "zero")))     //false

    println(numbers.isEmpty())          //false
    println(numbers.isNotEmpty())       //true
    println(numbers.isNullOrEmpty())    //false

    val empty = emptyList<String>()
    println(empty.isEmpty())            //true

}

fun retrievingCollectionParts() {
    println("------------------------------------Retrieving Collection Parts Demo------------------------------------")
    val numbers = listOf("one", "two", "three", "four", "five", "six")
    //slice
    println("-----------------slice-----------------")
    println(numbers.slice(1..3))            //[two, three, four]
    println(numbers.slice(0..4 step 2))     //[one, three, five]
    println(numbers.slice(setOf(3, 5, 0)))         //[four, six, one]

    //take and drop
    println("-----------------take and drop------------------")
    println(numbers.take(3))        //[one, two, three]
    println(numbers.takeLast(3))    //[four, five, six]
    println(numbers.drop(1))        //[two, three, four, five, six]
    println(numbers.dropLast(5))    //[one]

    println(numbers.takeWhile { !it.startsWith('f') })  //[one, two, three]
    println(numbers.takeLastWhile { it != "three" })         //[four, five, six]
    println(numbers.dropWhile { it.length == 3 })            //[three, four, five, six]
    println(numbers.dropLastWhile { it.contains('i') }) //[one, two, three, four]

    //Chunked(切块)
    println("-----------------chunked------------------")
    val numbers1 = (0..13).toList()
    println(numbers1.chunked(3))    //[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12, 13]]
    println(numbers1.chunked(3) { it.sum() })   //[3, 12, 21, 30, 25]
    val codonTable = mapOf("ATT" to "Isoleucine", "CAA" to "Glutamine", "CGC" to "Arginine", "GGC" to "Glycine")
    val dnaFragment = "ATTCGCGGCCGCCAA"
    val proteins =
        dnaFragment.chunked(3) { codon: CharSequence -> codonTable[codon.toString()] ?: error("Unknown codon") }
    println(proteins) // [Isoleucine, Arginine, Glycine, Arginine, Glutamine]

    //Windowed
    println("-----------------windowed------------------")
    println(numbers.windowed(3))    //[[one, two, three], [two, three, four], [three, four, five], [four, five, six]]
    val numbers2 = (1..10).toList()
    println(numbers2.windowed(3, step = 2, partialWindows = true))  //[[1, 2, 3], [3, 4, 5], [5, 6, 7], [7, 8, 9], [9, 10]]
    println(numbers2.windowed(3) { it.sum() })  //[6, 9, 12, 15, 18, 21, 24, 27]

}

fun ordering() {
    data class Person(var name: String, var age: Int)
    var personList: MutableList<Person> = mutableListOf()
    personList.add(Person("Jim", 12))
    personList.add(Person("A-Lin", 12))
    personList.add(Person("Tom", 11))
    personList.add(Person("Mary", 14))
    personList.add(Person("Tom", 14))

    println("------------------------------------Ordering Demo------------------------------------")
    val numbers1 = mutableListOf(4, 2, 3, 1)
    val numbers2 = listOf("one", "two", "three", "four")
    //Natural order
    println("-----------------Natural order------------------")
    numbers1.sort()
    println("Sort ascending: $numbers1")    //[1, 2, 3, 4]
    numbers1.sortDescending()   //[4, 3, 2, 1]
    println("Sort dscending: $numbers1")    //[1, 2, 3, 4]
    numbers1.sortWith(reverseOrder())
    println("SortWith reversed: $numbers1")    //[1, 2, 3, 4]
    personList.sortWith(compareBy({ it.age }, { it.name }))
    println(personList)
    personList.sortWith(compareBy<Person>{ it.name }.thenBy{it.age})
    println(personList)
    println("Sorted ascending: ${numbers2.sorted()}")   //[four, one, three, two]
    println("Sorted descending: ${numbers2.sortedDescending()}")    //[two, three, one, four]
    //Custom order
    println("-----------------Custom order------------------")
    val sortedNumbers = numbers2.sortedBy { it.length }
    println("Sorted by length ascending: $sortedNumbers")   //[one, two, four, three]
    val sortedByLast = numbers2.sortedByDescending { it.last() }
    println("Sorted by the last letter descending: $sortedByLast")  // [four, two, one, three]
    println("SortedWith compareBy: ${numbers2.sortedWith(compareBy{it.length})}")  //[one, two, four, three]
    println("SortedWith new comparator: ${numbers2.sortedWith(Comparator { str1: String, str2: String -> str1.length - str2.length })}")  //[one, two, four, three]

    //Reverse order
    println("-----------------Reverse order------------------")
    println("number1:$numbers1")    //[4, 3, 2, 1]
    numbers1.reverse()
    println("number1 reverse:$numbers1")    //[1, 2, 3, 4]
    val numbers3 = mutableListOf("one", "two", "three", "four")
    val reversedNumbers1 = numbers3.reversed()
    println("Before add five: $reversedNumbers1")    //[four, three, two, one]
    numbers3.add("five")
    println("After add five :$reversedNumbers1")    //[four, three, two, one]
    val reversedNumbers2 = numbers3.asReversed()
    println("Before add six $reversedNumbers2")      // [five, four, three, two, one]
    numbers3.add("six")
    println("After add six :$reversedNumbers2")     //[six, five, four, three, two, one]
    //Random order
    println("-----------------Random order------------------")
    println("shuffled:${numbers2.shuffled()}")      //[one, three, two, four]
    numbers3.shuffle()
    println("shuffle:$numbers3")    //[one, two, three, four, five, six]
}

fun aggregate() {
    println("------------------------------------Aggregate Demo------------------------------------")
    val numbers = listOf(5, 42, 10, 4)
    println("Count: ${numbers.count()}")        //4
    println("Max: ${numbers.maxOrNull ()}")            //42
    println("Min: ${numbers.minOrNull()}")            //4
    println("Average: ${numbers.average()}")    //15.25
    println("Sum: ${numbers.sum()}")            //41

    val min3Remainder = numbers.minByOrNull { it % 3 }
    println("minBy:$min3Remainder")            //42
    //两种参数，效果相同
    println("maxBy1:${products1.maxByOrNull { it.price }}")     //'computer' for 2200.0
    println("maxBy2:${products1.maxByOrNull(XProduct::price)}") //'computer' for 2200.0

    val strings = listOf("one", "two", "three", "four")
    val longestString = strings.maxWithOrNull(compareBy { it.length })
    println("maxWith:$longestString")   //three
    println("sumBy:${numbers.sumBy { it * 2 }}")    //122
    println("sumByDouble:${numbers.sumByDouble { it.toDouble() / 2 }}")  //30.5
    //reduce:无初值  fold：有初值；   参数1：代表集合第一个元素或初值，及其运算后的结果  参数2：遍历集合的所有元素
    val sum = numbers.reduce { sum, element -> sum + element * 2 }
    println("reduce:$sum")  //117
    val sumDoubled = numbers.fold(3) { msum, element -> msum + element * 2 }
    println("fold:$sumDoubled") //125
    val sumDoubledRight = numbers.foldRight(0) { element, msum -> msum + element * 2 }
    println("foldRight:$sumDoubledRight")   //122
    val sumEven = numbers.foldIndexed(0) { idx, msum, element -> if (idx % 2 == 0) msum + element else sum }
    println("foldIndexed:$sumEven")  //15
    val sumEvenRight = numbers.foldRightIndexed(1) { idx, element, msum -> if (idx % 2 == 0) msum + element else msum }
    println("foldRightIndexed:$sumEvenRight")   //16

    val numbers1 = listOf(3, 4, 5, 6, 7, 8, 9)
    val aggregated = numbers1.groupingBy { it % 3 }.aggregate { key, accumulator: StringBuilder?, element, first ->
        if (first) // first element
            StringBuilder().append(key).append(":").append(element)
        else
            accumulator!!.append("-").append(element)
    }
    println("aggregate :${aggregated.values}") // [0:3-6-9, 1:4-7, 2:5-8]

    val aggregated1 = numbers1.groupingBy { it % 3 }.aggregateTo(mutableMapOf()) { key, accumulator: Int?, element, first ->
        if (first) // first element
            element
        else
            accumulator!!+element
    }
    println("aggregateTo :$aggregated1") // {0=18, 1=11, 2=13}
    aggregated1.clear()
}

fun grouping() {
    println("------------------------------------Grouping Demo------------------------------------")
    val numbers = listOf("one", "two", "three", "four", "five")
    println(numbers.groupBy { it.first().toUpperCase() })   //{O=[one], T=[two, three], F=[four, five]}
    println(numbers.groupBy(keySelector = { it.first() }, valueTransform = { it.toUpperCase() }))   //{o=[ONE], t=[TWO, THREE], f=[FOUR, FIVE]}
    println(numbers.groupingBy { it.first() }.eachCount())  //{o=1, t=2, f=2}
}

fun writing() {
    println("------------------------Collection Write Operations Demo-------------------------")
    //Adding elements
    println("-----------------Adding elements------------------")
    val numbers = mutableListOf(1, 2, 3, 4)

    numbers.add(5)
    numbers.add(1, 6)
    println(numbers)  //[1, 6, 2, 3, 4, 5]

    numbers.addAll(arrayOf(7, 8))
    numbers.addAll(3, listOf(9, 10))
    println(numbers)    //[1, 6, 2, 9, 10, 3, 4, 5, 7, 8]
    numbers.addAll(2, setOf(3, 0))
    println(numbers)    //[1, 6, 3, 0, 2, 9, 10, 3, 4, 5, 7, 8]


    numbers += 9
    println(numbers)    //[1, 6, 3, 0, 2, 9, 10, 3, 4, 5, 7, 8, 9]
    numbers += listOf(11, 12)
    println(numbers)    //[1, 6, 3, 0, 2, 9, 10, 3, 4, 5, 7, 8, 9, 11, 12]

    val numbersMap = mutableMapOf("one" to 1, "two" to 2)
    numbersMap.put("three", 3)
    println(numbersMap) //{one=1, two=2, three=3}
    numbersMap.putAll(setOf("four" to 4, "five" to 5))
    println(numbersMap) //{one=1, two=2, three=3, four=4, five=5}
    numbersMap["six"] = 6
    println(numbersMap) //{one=1, two=2, three=3, four=4, five=5, six=6}
    numbersMap += mapOf("seven" to 7, "eight" to 8)
    println(numbersMap) //{one=1, two=2, three=3, four=4, five=5, six=6, seven=7, eight=8}
    println(numbersMap.getOrPut("x") { 2 }) // 2
    println(numbersMap.getOrPut("x") { 3 }) // 2
    println(numbersMap) //{one=1, two=2, three=3, four=4, five=5, six=6, seven=7, eight=8, x=2}

    //不改变原map，而是生成新的map
    println(numbersMap + Pair("nine", 9))   //{one=1, two=2, three=3, four=4, five=5, six=6, seven=7, eight=8, x=2, nine=9}
    println(numbersMap + Pair("one", 10))   //{one=10, two=2, three=3, four=4, five=5, six=6, seven=7, eight=8, x=2}
    println(numbersMap + mapOf("ten" to 10, "eleven" to 11)) //{one=1, two=2, three=3, four=4, five=5, six=6, seven=7, eight=8, x=2, ten=10, eleven=11}
    println(numbersMap - "one")         //{two=2, three=3, four=4, five=5, six=6, seven=7, eight=8, x=2}
    println(numbersMap - listOf("two", "four")) //{one=1, three=3, five=5, six=6, seven=7, eight=8, x=2}
    //update
    println("-----------------Updating elements------------------")
//    val numbers1 = mutableListOf(1, 2, 3, 4)
    numbers[0] = 0
    println(numbers)    //[0, 6, 3, 0, 2, 9, 10, 3, 4, 5, 7, 8, 9, 11, 12]
    numbers.fill(3)
    println(numbers)    //[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
    numbers.replaceAll { numbers.indexOf(it) + it.inc() }
    println(numbers)    //[4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]

    numbersMap["three"] = 13   // calls numbersMap.put("three", 13)
    numbersMap += mapOf("four" to 14, "five" to 15)
    println(numbersMap)     //{one=1, two=2, three=13, four=14, five=15, six=6, seven=7, eight=8, x=2}
    //remove
    println("-----------------Removing elements------------------")
    numbers.remove(13)                    // removes the first `3`
    println(numbers)            //[4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18]
    numbers.remove(50)                   // removes nothing
    println(numbers)            //[4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18]
    numbers.removeAt(1)
    println(numbers)            //[4, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18]

    numbers -= 9
    println(numbers)            //[4, 6, 7, 8, 10, 11, 12, 14, 15, 16, 17, 18]
    numbers -= listOf(10, 11)
    println(numbers)            //[4, 6, 7, 8, 12, 14, 15, 16, 17, 18]

    numbers.removeAll(setOf(4, 5))
    println(numbers)            //[6, 7, 8, 12, 14, 15, 16, 17, 18]
    numbers.retainAll { it >= 15 }
    println(numbers)            //[15, 16, 17, 18]
    numbers.clear()
    println(numbers)            //[]

    numbersMap.remove("one")
    println(numbersMap)         //{two=2, three=13, four=14, five=15, six=6, seven=7, eight=8, x=2}
    numbersMap.remove("three", 3)            //doesn't remove anything
    println(numbersMap)         //{two=2, three=13, four=14, five=15, six=6, seven=7, eight=8, x=2}
    numbersMap.keys.remove("two")
    println(numbersMap)         //{three=13, four=14, five=15, six=6, seven=7, eight=8, x=2}
    numbersMap.values.remove(13)
    println(numbersMap)         //{four=14, five=15, six=6, seven=7, eight=8, x=2}
    numbersMap -= "four"
    println(numbersMap)         //{five=15, six=6, seven=7, eight=8, x=2}
    numbersMap -= "ten"                     //doesn't remove anything
    println(numbersMap)         //{five=15, six=6, seven=7, eight=8, x=2}
}

fun plusAndMinus() {
    println("------------------------plus and minus Operators Demo-------------------------")
    val numbers = listOf("one", "two", "three", "four")  //[one, two, three, four]
    val plusList1 = numbers + "five"                            //[one, two, three, four, five]
    val plusList2 = numbers + listOf("three", "four")           //[one, two, three, four, three, four]
    val minusList1 = plusList2 - "three"                        //[one, two, four, three, four]
    val minusList2 = plusList2 - listOf("three", "four")        //[one, two]
    log("List",numbers,plusList1,plusList2,minusList1,minusList2)


    //不改变原map，而是生成新的map
    val numbersMap = mapOf("one" to 1, "two" to 2)
    println(numbersMap + Pair("three", 3))                  //{one=1, two=2, three=3}
    println(numbersMap + Pair("one", 10))                   //{one=10, two=2}
    println(numbersMap + mapOf("four" to 4, "five" to 5))   //{one=1, two=2, four=4, five=5}
    println(numbersMap - "one")                             //{two=2}
    println(numbersMap - listOf("two", "four"))             //{one=1}
    println(numbersMap)                                     //{one=1, two=2}
}

fun Customer.getOrderedProducts(): List<XProduct> = orders.flatMap{it.products}

fun <T> log(tip:String,vararg s:T){
    s.forEach {println("$tip: $it")}
}

fun <T> printAll(tip:String,vararg s:T){
    print("$tip:" )
    s.forEachIndexed {index, t ->  if (index==s.lastIndex) print("$t") else  print("$t ; ")}
    println()
}

