Groovy/FAQ/Массивы
Материал из Wiki.crossplatform.ru
Версия от 09:04, 8 декабря 2008; Root (Обсуждение | вклад)
Groovy · |
Introduction
//---------------------------------------------------------------------------------- simple = [ "this", "that", "the", "other" ] nested = [ "this", "that", [ "the", "other" ] ] assert nested.size() == 3 assert nested[2].size() == 2 flattenNestedToSimple = [ "this", "that", [ "the", "other" ] ].flatten() assert flattenNestedToSimple.size() == 4 //----------------------------------------------------------------------------------
Specifying a List In Your Program
//---------------------------------------------------------------------------------- a = [ "quick", "brown", "fox" ] assert a.size() == 3 a = 'Why are you teasing me?'.split(' ') assert a == ["Why", "are", "you", "teasing", "me?"] removeLeadingSpaces = { it.trim() } nonBlankLines = { it } lines = ''' The boy stood on the burning deck, It was as hot as glass. '''.split('\n').collect(removeLeadingSpaces).findAll(nonBlankLines) assert lines == ["The boy stood on the burning deck,", "It was as hot as glass."] // initialiseListFromFileScript: lines = new File('mydata.txt').readLines() // processFileScript: new File('mydata.txt').eachLine{ // dosomething } //----------------------------------------------------------------------------------
Printing a List with Commas
//---------------------------------------------------------------------------------- marbleColors = ['red', 'green', 'yellow'] assert marbleColors.join(', ') == 'red, green, yellow' def commify(items) { if (!items) return items def sepchar = items.find{ it =~ /,/ } ? '; ' : ', ' switch (items.size()) { case 1: return items[0] case 2: return items.join(' and ') } items[0..-2].join(sepchar) + sepchar + 'and ' + items[-1] } assert commify(marbleColors) == 'red, green, and yellow' lists = [ [ 'just one thing' ], [ 'Mutt', 'Jeff' ], 'Peter Paul Mary'.split(' '), [ 'To our parents', 'Mother Theresa', 'God' ], [ 'pastrami', 'ham and cheese', 'peanut butter and jelly', 'tuna' ], [ 'recycle tired, old phrases', 'ponder big, happy thoughts' ], [ 'recycle tired, old phrases', 'ponder big, happy thoughts', 'sleep and dream peacefully' ], ] expected = ''' just one thing Mutt and Jeff Peter, Paul, and Mary To our parents, Mother Theresa, and God pastrami, ham and cheese, peanut butter and jelly, and tuna recycle tired, old phrases and ponder big, happy thoughts recycle tired, old phrases; ponder big, happy thoughts; and sleep and dream peacefully ''' assert expected == '\n' + lists.collect{commify(it)}.join('\n') + '\n' //----------------------------------------------------------------------------------
Changing Array Size
//---------------------------------------------------------------------------------- // In Groovy, lists and arrays are more or less interchangeable // here is the example using lists people = ['Crosby', 'Stills', 'Nash'] assert people.size() == 3 people[3] = 'Young' assert people.size() == 4 assert people == ['Crosby', 'Stills', 'Nash', 'Young'] // to use arrays simply do 'people = peopleArray.toList()' at the start // and 'peopleArray = people as String[]' at the end // if you attempt to do extension on a Java array you will get an // ArrayIndexOutOfBoundsException - which is why Java has ArrayList et al //----------------------------------------------------------------------------------
Doing Something with Every Element in a List
//---------------------------------------------------------------------------------- // list to process people == ['Crosby', 'Stills', 'Nash', 'Young'] // helper startsWithCapital = { word -> word[0] in 'A'..'Z' } // various styles are possible for processing lists // closure style people.each { person -> assert startsWithCapital(person) } // for loop style for (person in people) { assert startsWithCapital(person) } // unixScriptToFindAllUsersStartingWithLetterA: all = 'who'.execute().text.replaceAll('\r', '').split('\n') all.grep(~/^a.*/).each{ println it } // printFileWithWordsReversedScript: new File('Pleac/src/SlowCat.groovy').eachLine{ line -> line.split(' ').each{ print it.reverse() } } a = [0.5, 3]; b = [0, 1] assert [a, b].flatten().collect{ it * 7 } == [3.5, 21, 0, 7] // above doesn't modify original arrays // instead use a = a.collect{ ... } //----------------------------------------------------------------------------------
Iterating Over an Array by Reference
//---------------------------------------------------------------------------------- // not relevant in Groovy since we have always references items = [] for (item in items) { // do something with item } //----------------------------------------------------------------------------------
Extracting Unique Elements from a List
//---------------------------------------------------------------------------------- assert [ 1, 1, 2, 2, 3, 3, 3, 5 ].unique() == [ 1, 2, 3, 5 ] //----------------------------------------------------------------------------------
Finding Elements in One Array but Not Another
//---------------------------------------------------------------------------------- assert [ 1, 1, 2, 2, 3, 3, 3, 4, 5 ] - [ 1, 2, 4 ] == [3, 3, 3, 5] assert [ 1, 1, 2, 2, 3, 3, 3, 4, 5 ].unique() - [ 1, 2, 4 ] == [3, 5] //----------------------------------------------------------------------------------
Computing Union, Intersection, or Difference of Unique Lists
//---------------------------------------------------------------------------------- a = [1, 3, 5, 6, 7, 8] b = [2, 3, 5, 7, 9] // intersection assert a.intersect(b) == [3, 5, 7] // union assert (a + b).unique().sort() == [1, 2, 3, 5, 6, 7, 8, 9] // difference assert (a - b) == [1, 6, 8] //----------------------------------------------------------------------------------
Appending One Array to Another
//---------------------------------------------------------------------------------- members = [ "Time", "Flies" ] initiates = [ "An", "Arrow" ] members += initiates assert members == ["Time", "Flies", "An", "Arrow"] members.add(2, "Like") assert members == ["Time", "Flies", "Like", "An", "Arrow"] members[0] = "Fruit" members[3..4] = ["A", "Banana"] assert members == ["Fruit", "Flies", "Like", "A", "Banana"] //----------------------------------------------------------------------------------
Reversing an Array
//---------------------------------------------------------------------------------- items = ["the", "quick", "brown", "fox"] assert items.reverse() == ["fox", "brown", "quick", "the"] firstLetters = [] items.reverseEach{ firstLetters += it[0] } assert firstLetters.join() == 'fbqt' descending = items.sort().reverse() assert descending == ["the", "quick", "fox", "brown"] descendingBySecondLastLetter = items.sort { a,b -> b[-2] <=> a[-2] } assert descendingBySecondLastLetter == ["brown", "fox", "the", "quick"] //----------------------------------------------------------------------------------
Processing Multiple Elements of an Array
//---------------------------------------------------------------------------------- // warning: not an exact equivalent, idiomatic use would return copies def shift2 = {one = friends[0]; two = friends[1]; 2.times{friends.remove(0)}} friends = 'Peter Paul Mary Jim Tim'.split(' ').toList() shift2() assert one == 'Peter' assert two == 'Paul' assert friends == ["Mary", "Jim", "Tim"] def pop2(items) { items[0..1] } beverages = 'Dew Jolt Cola Sprite Fresca'.split(' ').toList() pair = pop2(beverages) assert pair == ["Dew", "Jolt"] //----------------------------------------------------------------------------------
Finding the First List Element That Passes a Test
//---------------------------------------------------------------------------------- class Employee { def name def position def salary } staff = [new Employee(name:'Jim',position:'Manager',salary:26000), new Employee(name:'Jill',position:'Engineer',salary:24000), new Employee(name:'Jack',position:'Engineer',salary:22000)] highestEngineer = staff.find { emp -> emp.position == 'Engineer' } assert highestEngineer.salary == 24000 //----------------------------------------------------------------------------------
Finding All Elements in an Array Matching Certain Criteria
//---------------------------------------------------------------------------------- engineers = staff.findAll { e -> e.position == 'Engineer' } assert engineers.size() == 2 highPaid = staff.findAll { e -> e.salary > 23000 } assert highPaid*.name == ["Jim", "Jill"] //----------------------------------------------------------------------------------
Sorting an Array Numerically
//---------------------------------------------------------------------------------- // sort works for numbers assert [100, 3, 20].sort() == [3, 20, 100] // strings representing numbers will be sorted alphabetically assert ['100', '3', '20'].sort() == ["100", "20", "3"] // closure style sorting allows arbitrary expressions for the comparison assert ['100', '3', '20'].sort{ a,b -> a.toLong() <=> b.toLong()} == ["3", "20", "100"] // obtain the following on unix systems using: 'ps ux'.execute().text processInput = ''' PID PPID PGID WINPID TTY UID STIME COMMAND 3868 1 3868 3868 con 1005 06:23:34 /usr/bin/bash 3456 3868 3456 3528 con 1005 06:23:39 /usr/bin/ps ''' nonEmptyLines = {it.trim()} lines = processInput.split("\n").findAll(nonEmptyLines)[1..-1] def col(n, s) { s.tokenize()[n] } commandIdx = 7 pidIdx = 0 ppidIdx = 1 linesByPid = lines.sort{ col(pidIdx,it).toLong() } assert col(commandIdx, linesByPid[0]) == '/usr/bin/ps' linesByPpid = lines.sort{ col(ppidIdx,it).toLong() } assert col(commandIdx, linesByPpid[0]) == '/usr/bin/bash' //----------------------------------------------------------------------------------
Sorting a List by Computable Field
//---------------------------------------------------------------------------------- // sort staff from 4.12 by name assert staff.sort { a,b -> a.name <=> b.name }*.name == ["Jack", "Jill", "Jim"] // sort by first two characters of name and if equal by descending salary assert staff.sort { a,b -> astart = a.name[0..1] bstart = b.name[0..1] if (astart == bstart) return b.salary <=> a.salary return astart <=> bstart }*.name == ["Jack", "Jim", "Jill"] //----------------------------------------------------------------------------------
Implementing a Circular List
//---------------------------------------------------------------------------------- items = [1, 2, 3, 4, 5] processed = [] 10.times{ processed << items[0] items = items[1..-1] + items[0] } assert processed == [1, 2, 3, 4, 5, 1, 2, 3, 4, 5] //----------------------------------------------------------------------------------
Randomizing an Array
//---------------------------------------------------------------------------------- import java.text.DateFormatSymbols as Symbols items = new Symbols().shortWeekdays.toList()[1..7] assert items == ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"] // not as random as you might expect println items.sort{ Math.random() } // => ["Sat", "Tue", "Sun", "Wed", "Mon", "Thu", "Fri"] // better to use the built-in method for this purpose Collections.shuffle(items) println items // => ["Wed", "Tue", "Fri", "Sun", "Sat", "Thu", "Mon"] //----------------------------------------------------------------------------------
Program: words
//---------------------------------------------------------------------------------- symbols = new Symbols() words = symbols.weekdays.toList()[1..7] + symbols.months.toList()[0..11] + symbols.eras.toList() + symbols.amPmStrings.toList() expected = // 'AD August February July May October September Tuesday \n' + 'AM BC Friday June Monday PM Sunday Wednesday \n' + 'April December January March November Saturday Thursday \n' class WordFormatter { def cols def process(list) { def sb = new StringBuffer() def colWidth = list.max{it.size()}.size() + 1 int columns = [cols/colWidth, 1].max() def numWords = list.size() int rows = (numWords + columns - 1) / columns for (row in 0..<rows) { for (col in 0..<columns) { def target = row + col * rows if (target < numWords) sb << list[target].padRight(colWidth) } sb << '\n' } return sb.toString() } } // get nr of chars that fit in window or console, see PLEAC 15.4 // hard-coded here but several packages are available, e.g. in JLine // use a concrete implementation of Terminal.getTerminalWidth() def getWinCharWidth() { 80 } // main script actual = new WordFormatter(cols:getWinCharWidth()).process(words.sort()) assert actual == expected //----------------------------------------------------------------------------------
Program: permute
//---------------------------------------------------------------------------------- // recursive version is simplest but can be inefficient def fact(n) { (n == 1) ? 1 : n * fact(n-1)} assert fact(10) == 3628800 // unwrapped version: note use of BigInteger def factorial(n) { def result = 1G // 1 as BigInteger while (n > 0) { result *= n n -= 1 } return result } expected = 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 assert expected == factorial(100) // println factorial(10000) // => 284625... (greater than 35,000 digits) // simple version but less efficient def simplePermute(items, perms) { if (items.size() == 0) println perms.join(' ') else for (i in items) { newitems = items.clone() newperms = perms.clone() newperms.add(i) newitems.remove(i) simplePermute(newitems, newperms) } } simplePermute(['dog', 'bites', 'man'], []) // => //dog bites man //dog man bites //bites dog man //bites man dog //man dog bites //man bites dog // optimised version below expected = ''' man bites dog man dog bites bites man dog bites dog man dog man bites dog bites man ''' // n2pat(n, len): produce the N-th pattern of length len def n2pat(n, length) { def pat = [] int i = 1 while (i <= length) { pat << (n % i) n = n.intdiv(i) i += 1 } pat } // pat2perm(pat): turn pattern returned by n2pat() into // permutation of integers. def pat2perm(pat) { def source = (0 ..< pat.size()).collect{ it/*.toString()*/ } def perm = [] while (pat.size() > 0) { def next = pat.remove(pat.size()-1) perm << source[next] source.remove(next) } perm } def n2perm(n, len) { pat2perm(n2pat((int)n,len)) } data = ['man', 'bites', 'dog'] sb = new StringBuffer() numPermutations = fact(data.size()) for (j in 0..<numPermutations) { def permutation = n2perm(j, data.size()).collect { k -> data[k] } sb << permutation.join(' ') + '\n' } assert '\n' + sb.toString() == expected //----------------------------------------------------------------------------------