groovy-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dinko Srkoč <dinko.sr...@gmail.com>
Subject Re: String to Array of Substrings by delimiter
Date Sat, 27 Jun 2015 11:10:25 GMT
I know the solution has been found, but it’s a nice problem. Here’s my
contribution, however inapplicable…

This is the second time 1
<http://groovy.329449.n5.nabble.com/Find-sublists-adhering-to-some-rules-tp5720013p5720087.html>*,
I believe, that the method inits from the Scala collection API 2
<http://scala-lang.org/api/current/index.html#scala.collection.TraversableLike@inits:Iterator[Repr]>
seems usable. (is this enough to add it to groovy-jdk?)

inits returns successive application of init() on a collection:

[1, 2, 3].inits() would return [[1, 2, 3], [1, 2], [1], []]

The naive implementation of inits might look like this:

class Inits {
    static List<List> inits(List self) {
        (1..self.size()).inject([self]) { acc, _ ->
            acc << acc.last().init()
        }
    }
}

Finally, the solution:

String s = '/a/b/c/d'def expected = ['/a', '/a/b', '/a/b/c', '/a/b/c/d']

use (Inits) {
    def res = s.tokenize('/').inits().reverse().tail().collect {
        '/' + it.join('/')
    }
    assert res == expected
}

Cheers,
Dinko

(*) unlike before, unfortunately, this permalink won’t lead directly to my
post, one has to scroll to the bottom of the page to find it
​

On 26 June 2015 at 20:59, Steve Amerige <Steve.Amerige@sas.com> wrote:

>  Hi Shil,
>
> I like this... thanks!  I've made the following first improvements by
> using *tokenize *instead of *split *and using a single Groovy string to
> clean up the syntax a bit:
>
>     String s = '/a/b/c/d'
>     s.tokenize('/').inject([]) { acc, val -> acc + "${acc ? acc.last() :
> ''}/$val" }
>
> *    Result: [/a, /a/b, /a/b/c, /a/b/c/d]*
>
>
> Then, to get rid of the ternary logic, I thought about adding a *withDefault
> *expression so that I could safely use last():
>
>     String s = '/a/b/c/d'
>     s.tokenize('/').inject([]*.withDefault {''}*) { acc, val -> acc + "${
> *acc.last()*}/$val" }
>
> But the above throws *NoSuchElementException *when trying to reference
> *acc.last()*.  It does make sense: getting a default implies that an
> entry in the list gets created, but we don't want to create an object into
> the list.  So, one could add a delegate to solve this without dirtying the
> semantics of *last*:
>
>     String s = '/a/b/c/d'
>     List.metaClass.safelast = { delegate?.empty ? '' : delegate.last() }
>     s.tokenize('/').inject([]) { acc, val -> acc +
> "${acc.safelast()}/$val" }
>
> Thanks again Shil and Bahman for your ideas!
>
> Enjoy,
> Steve Amerige
>  Principal Software Developer, Fraud and Compliance Solutions Development
> SAS Institute, 100 SAS Campus Dr, Room U3050, Cary, NC 27513-8617
>
>
>
> On 6/26/2015 12:09 PM, Shil Sinha wrote:
>
> Not the best looking, but it's a one liner that works:
>
>   s.split('/').tail().inject([]) { acc, val -> acc + ((!acc.isEmpty() ?
> acc.last() : '') + "/$val") }
>
>
> On Fri, Jun 26, 2015 at 11:34 AM, Steve Amerige <Steve.Amerige@sas.com>
> wrote:
>
>>  Hi all,
>>
>> Suppose you have:
>>
>>     String s = '/a/b/c/d'     // guaranteed to begin with a / and have at
>> least one substring sequence after the /; can have more than 4 as shown in
>> this example
>>
>> and I want the result:
>>
>>     [ '/a', '/a/b', '/a/b/c', '/a/b/c/d' ]
>>
>> where '/' can be any single character delimiter.  What would be the
>> easiest, grooviest way to get that result?
>>
>
>

Mime
View raw message