Return-Path: X-Original-To: apmail-groovy-users-archive@minotaur.apache.org Delivered-To: apmail-groovy-users-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 0A22918F7B for ; Sat, 27 Jun 2015 11:11:03 +0000 (UTC) Received: (qmail 82607 invoked by uid 500); 27 Jun 2015 11:11:02 -0000 Delivered-To: apmail-groovy-users-archive@groovy.apache.org Received: (qmail 82574 invoked by uid 500); 27 Jun 2015 11:11:02 -0000 Mailing-List: contact users-help@groovy.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: users@groovy.incubator.apache.org Delivered-To: mailing list users@groovy.incubator.apache.org Received: (qmail 82564 invoked by uid 99); 27 Jun 2015 11:11:02 -0000 Received: from Unknown (HELO spamd3-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 27 Jun 2015 11:11:02 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd3-us-west.apache.org (ASF Mail Server at spamd3-us-west.apache.org) with ESMTP id 6738F180339 for ; Sat, 27 Jun 2015 11:11:02 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd3-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: 4.213 X-Spam-Level: **** X-Spam-Status: No, score=4.213 tagged_above=-999 required=6.31 tests=[DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, HTML_MESSAGE=3, SPF_PASS=-0.001, URIBL_BLOCKED=0.001, URI_HEX=1.313] autolearn=disabled Authentication-Results: spamd3-us-west.apache.org (amavisd-new); dkim=pass (2048-bit key) header.d=gmail.com Received: from mx1-us-west.apache.org ([10.40.0.8]) by localhost (spamd3-us-west.apache.org [10.40.0.10]) (amavisd-new, port 10024) with ESMTP id XgR0xcOZw7vL for ; Sat, 27 Jun 2015 11:10:53 +0000 (UTC) Received: from mail-wg0-f45.google.com (mail-wg0-f45.google.com [74.125.82.45]) by mx1-us-west.apache.org (ASF Mail Server at mx1-us-west.apache.org) with ESMTPS id 58F32211EF for ; Sat, 27 Jun 2015 11:10:52 +0000 (UTC) Received: by wgqq4 with SMTP id q4so106532878wgq.1 for ; Sat, 27 Jun 2015 04:10:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :content-type; bh=vgJZckIDZP6iH/APmz8HSPQj2F7YRk9f1NqWMKSCk0c=; b=TMVXSHnkOwRpwKl5nWqcnzn6dYsdgldfYNgBrYm5kVTFI0awcf2K1z2SD0htgvADSQ 0bjoJFIQ8JJmuvEBP0A8hUpE9wMEmIS8oqmcYOEUB3avKXeIM5Cejol4b4WKjYZi8o16 BukaEz8b1LnlYk1viKTieyLaX2IBrZqQF1O60BIxWgO1y1m/8EzIcf09PvJoMvYwHAHc ppov6ksu57sbJxwaVpFRKTtwmGyM65J2rHElZmv0TKQdghOa7GywGHneDCK+0eLas++w YyVOqhhTqRd4Ilz/8Hvo238VA8X3aQh+5ET3fUG8yOzhNB/2St1jYYLu8FgBRqct8YL7 SgDQ== X-Received: by 10.180.74.132 with SMTP id t4mr5304297wiv.55.1435403444845; Sat, 27 Jun 2015 04:10:44 -0700 (PDT) MIME-Version: 1.0 Received: by 10.28.21.75 with HTTP; Sat, 27 Jun 2015 04:10:25 -0700 (PDT) In-Reply-To: <558DA118.8000204@sas.com> References: <558D7119.4060100@sas.com> <558DA118.8000204@sas.com> From: =?UTF-8?B?RGlua28gU3Jrb8SN?= Date: Sat, 27 Jun 2015 13:10:25 +0200 Message-ID: Subject: Re: String to Array of Substrings by delimiter To: users@groovy.incubator.apache.org Content-Type: multipart/related; boundary=f46d043be06c717aae05197de856 --f46d043be06c717aae05197de856 Content-Type: multipart/alternative; boundary=f46d043be06c717aad05197de855 --f46d043be06c717aad05197de855 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable I know the solution has been found, but it=E2=80=99s a nice problem. Here= =E2=80=99s my contribution, however inapplicable=E2=80=A6 This is the second time 1 *, I believe, that the method inits from the Scala collection API 2 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 inits(List self) { (1..self.size()).inject([self]) { acc, _ -> acc << acc.last().init() } } } Finally, the solution: String s =3D '/a/b/c/d'def expected =3D ['/a', '/a/b', '/a/b/c', '/a/b/c/d'= ] use (Inits) { def res =3D s.tokenize('/').inits().reverse().tail().collect { '/' + it.join('/') } assert res =3D=3D expected } Cheers, Dinko (*) unlike before, unfortunately, this permalink won=E2=80=99t lead directl= y to my post, one has to scroll to the bottom of the page to find it =E2=80=8B On 26 June 2015 at 20:59, Steve Amerige 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 =3D '/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 *withDefa= ult > *expression so that I could safely use last(): > > String s =3D '/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 int= o > the list. So, one could add a delegate to solve this without dirtying th= e > semantics of *last*: > > String s =3D '/a/b/c/d' > List.metaClass.safelast =3D { 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 > wrote: > >> Hi all, >> >> Suppose you have: >> >> String s =3D '/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? >> > > --f46d043be06c717aad05197de855 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable

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

I like this... thanks!=C2=A0 I've made the following first improv= ements by using tokenize instead of split and using a single Groovy string to clean up the syntax a bit:

=C2=A0=C2=A0=C2=A0 String s =3D '/a/b/c/d'
=C2=A0=C2=A0=C2=A0 s.tokenize('/').inject([]) { acc, val = -> acc + "${acc ? acc.last() : ''}/$val" }


=C2=A0=C2=A0=C2=A0 Result: [/a, /= a/b, /a/b/c, /a/b/c/d]


Then, to get rid of the ternary logic, I thought about adding a wi= thDefault expression so that I could safely use last():

=C2=A0=C2=A0=C2=A0 String s =3D '/a/b= /c/d'
=C2=A0=C2=A0=C2=A0 s.tokenize('/').inject([].wi= thDefault {''}) { acc, val -> acc + "${acc.last()}/$val" }


But the above throws NoSuchElementException when trying to reference acc.last().=C2=A0 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.=C2=A0 So, one could= add a delegate to solve this without dirtying the semantics of last:=

=C2=A0=C2=A0=C2=A0 String s =3D '/a/b= /c/d'
=C2=A0=C2=A0=C2=A0 List.metaClass.safelast =3D { delegate?= .empty ? '' : delegate.last() }
=C2=A0=C2=A0=C2=A0 s.tokenize('/').inject([]) { ac= c, 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


3D""

On 6/26/2015 12:09 PM, Shil Sinha wrote:
=20
Not the best looking, but it's a one liner that works:

s.split('/').tail().inject([]) { acc, val -> ac= c + ((!acc.isEmpty() ? acc.last() : '') + "/$val&quo= t;) }


On Fri, Jun 26, 2015 at 11:34 AM, Steve Amerige <Steve.Amerige@sas.com> wrote:
Hi all,

Suppose you have:

=C2=A0=C2=A0=C2=A0 String s =3D '/a/b/c/d'=C2=A0=C2= =A0=C2=A0=C2=A0 // 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:

=C2=A0=C2=A0=C2=A0 [ '/a', '/a/b', '/a/b/= c', '/a/b/c/d' ]

where '/' can be any single character delimiter.=C2= =A0 What would be the easiest, grooviest way to get that result?


--f46d043be06c717aad05197de855-- --f46d043be06c717aae05197de856 Content-Type: image/gif; name="SAS_TPTK_logo.gif" Content-Disposition: inline; filename="SAS_TPTK_logo.gif" Content-Transfer-Encoding: base64 Content-ID: X-Attachment-Id: 4f8be4e8e024860a_0.1.1 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 DrOYx1yHEAAAOw== --f46d043be06c717aae05197de856--