16
\$\begingroup\$

Challenge

You task for this question is to split an input array of integers on the second occurrence of every integer in that array.

Not clear enough ? Here is an example to help

Input array:

[2 1 1 2 3 2 2 4 5 6 7 3 7 0 5]

Output:

[[2 1] [] [3 2 2 4 5 6 7] [] [0] []]

Explanation:

Here is the array with just the second element highlighted in bold:

[2 1 1 2 3 2 2 4 5 6 7 3 7 0 5]

Now we put the splitting array blocks around these bold second occurrences:

[2 1] 1 [] 2 [3 2 2 4 5 6 7] 3 [] 7 [0] 5 []

and wrap these splitted arrays in an array to get the final

[[2 1] [] [3 2 2 4 5 6 7] [] [0] []]

Note that when adjacent second occurrences occur, there will be empty arrays.

Rules

As usual, you have to write a full program or a function taking the input array via STDIN, ARGV or function argument.

Input

The input consists on any convenient array (or array-like) format of integers.

For instance, any of the following would be acceptable:

2 1 1 1 4 5 6
[2 1 1 1 4 5 6]
[2, 1, 1, 1, 4, 5, 6]

Output

When outputting to STDOUT, your array can also be printed in any convenient (nested) array format, e.g. one of

[[2 1] [1 4 5 6]]
[[2, 1], [1, 4, 5, 6]]
{{2, 1}, {1, 4, 5, 6}}

(This will usually be the native string representation of arrays in your language.)

Also note that trailing empty arrays should be printed as the part of the array.

Scoring

This is so shortest code in bytes win!

\$\endgroup\$
5
  • \$\begingroup\$ @PeterTaylor many questions allow for different formats of arrays in both output and inputl. \$\endgroup\$
    – Optimizer
    Commented Dec 20, 2014 at 12:30
  • 5
    \$\begingroup\$ What's the point of allowing "" as the empty array? This smells of favourism towards a specific golfing language. \$\endgroup\$ Commented Dec 20, 2014 at 12:46
  • 1
    \$\begingroup\$ @JanDvorak After discussion in chat, the intention was actually to be more inclusive and generally allow languages to use their native representation. I've edited the wording now to make that clearer. \$\endgroup\$ Commented Dec 20, 2014 at 12:56
  • 1
    \$\begingroup\$ Can I just output 2 1, 1 4 5 6? \$\endgroup\$
    – jimmy23013
    Commented Dec 20, 2014 at 14:41
  • \$\begingroup\$ @user23013 depends on the language you have chosen. \$\endgroup\$
    – Optimizer
    Commented Dec 20, 2014 at 14:43

24 Answers 24

9
\$\begingroup\$

APL (Dyalog 14) (31)

{1↓¨(1,(⍳⍴⍵)∊2⍳⍨¨↓+\∘.=⍨⍵)⊂0,⍵}

This is a function that takes an array and returns a nested array.

Test:

      +V← {1↓¨(1,(⍳⍴⍵)∊2⍳⍨¨↓+\∘.=⍨⍵)⊂0,⍵} 2 1 1 2 3 2 2 4 5 6 7 3 7 0 5
┌───┬┬─────────────┬┬─┬┐
│2 1││3 2 2 4 5 6 7││0││
└───┴┴─────────────┴┴─┴┘
      ⍝ this return value is a real nested array:
      ⎕←'Length: ',⍴V ⋄ (⍳⍴V){⎕←'Array #',⍺,': (', ⍵, ')'}¨V 
Length:  6
Array # 1 : ( 2 1 )
Array # 2 : ()
Array # 3 : ( 3 2 2 4 5 6 7 )
Array # 4 : ()
Array # 5 : ( 0 )
Array # 6 : ()

Explanation:

  • 0,⍵: Add a 0 to the front of , for easier processing. (It does not count as an occurrence.)
  • (...)⊂: Split the array according to the given bitmask. A new group starts at each 1 in the bitmask.
    • +\∘.=⍨⍵: for each value in (the original) , find all occurrences in . Then make a running sum for each value, giving a square matrix showing for each position in how many of each value have already occurred.
    • : Split the matrix by its rows, giving for each value an array showing the amount of times it has occurred by each position.
    • 2⍳⍨¨: In each of these arrays, find the index of the first 2.
    • (⍳⍴⍵)∊: For each possible index into , see if it is contained in the list of indices of second occurrences. (These start each group, except the first one.)
    • 1,: Add an 1 to the front, marking the start of the first group.
  • 1↓¨: Remove the first element from each group. (These are the added 0, and the second occurrence of each value.)
\$\endgroup\$
8
\$\begingroup\$

J, 28 24 char

Special thanks to randomra.

(1&,<;._1~1,2=+/@(={:)\)

It works like this. Over all prefixes (\) of the input array, we look at how many (+/@) elements of the prefix are equal to the last element (={:) of that prefix. When this number is 2, we know this is the second occurrence of that item in the array, so we split the array there using <;._1.

   a=.2 1 1 2 3 2 2 4 5 6 7 3 7 0 5
   (={:)\ a
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 1 0 0 0 0 0 0 0 0 0 0 0 0
1 0 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
1 0 0 1 0 1 0 0 0 0 0 0 0 0 0
1 0 0 1 0 1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0 1 0 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 1
   +/@(={:)\ a
1 1 2 2 1 3 4 1 1 1 1 2 2 1 2

Old thing using sort tricks: (1&,<;._1~1,1=i.~(]-{)/:@/:).

\$\endgroup\$
1
  • \$\begingroup\$ (1&,<;._1~1,2=+/@(={:)\) is 4 bytes shorter and a lot simpler. (/:@/: is a nice trick though.) \$\endgroup\$
    – randomra
    Commented Mar 27, 2015 at 12:33
7
\$\begingroup\$

APL 25

1↓¨(1,∨⌿<\2=+\∘.=⍨a)⊂1,a←

Example:

]display 1↓¨(1,∨⌿<\2=+\∘.=⍨a)⊂1,a←2 1 1 2 3 2 2 4 5 6 7 3 7 0 5
┌→──────────────────────────────────────┐
│ ┌→──┐ ┌⊖┐ ┌→────────────┐ ┌⊖┐ ┌→┐ ┌⊖┐ │
│ │2 1│ │0│ │3 2 2 4 5 6 7│ │0│ │0│ │0│ │
│ └~──┘ └~┘ └~────────────┘ └~┘ └~┘ └~┘ │
└∊──────────────────────────────────────┘

Old One:

{1↓¨(1,(⍳⍴⍵)∊,{1↑1↓⍵}⌸⍵)⊂1,⍵}

This is a nice question for the key operator (⌸) which was introduced with Dyalog APL v14. It takes the left argument function ({1↑1↓⍵}) and gives it for each unique argument, the indices in the vector for that argument. Here I'm taking the second index, then i check which of the indices is present in this list ((⍳⍴⍵)∊) and use the resulting boolean for splitting the original vector.

Can be tried online here:

http://tryapl.org

\$\endgroup\$
4
  • \$\begingroup\$ Damn. Still not less than 24 ? \$\endgroup\$
    – Optimizer
    Commented Dec 23, 2014 at 11:47
  • \$\begingroup\$ @Optimizer: 25... I'm trying ;-) \$\endgroup\$ Commented Dec 23, 2014 at 14:01
  • \$\begingroup\$ Accepting this instead of my own solution :) \$\endgroup\$
    – Optimizer
    Commented Jan 6, 2015 at 17:01
  • 1
    \$\begingroup\$ Only 24, and a proper function: 1↓¨{1,∨⌿<\2=+\∘.=⍨⍵}⊂1∘, \$\endgroup\$
    – Adám
    Commented Dec 20, 2016 at 16:21
7
\$\begingroup\$

Mathematica, 58 51 49 bytes

Rest/@SplitBy[(f@#=0;#)&/@{a}~Join~#,++f[#]==3&]&

This is an unnamed function which takes a list like

Rest/@SplitBy[(f@#=0;#)&/@{a}~Join~#,++f[#]==3&]&[{2,1,1,2,3,2,2,4,5,6,7,3,7,0,5}]

and returns a nested list like

{{2, 1}, {}, {3, 2, 2, 4, 5, 6, 7}, {}, {0}, {}}

How it works

This uses some pretty obscure magic with SplitBy.

I'm keeping track of the occurrences of each number in a function f. In Mathematica, you can define the value of a function for each input separately, and you don't need to specify the value for all possible inputs (it's more like a hash table on steroids).

So I start out by initialising f to 0 for values that are present in the input with (f@#=0;#)&/@.

Now SplitBy takes a list and a function and "splits list into sublists consisting of runs of successive elements that give the same value when f is applied" (note that SplitBy does not remove any elements). But the (undocumented) catch is, that f is called twice on each element - when comparing it to its predecessor and its successor. So if we do

 SplitBy[{1,2,3,4},Print]

we don't just get each number once, but instead this prints

 1
 2
 2
 3
 3
 4

which is 6 calls for 3 comparisons.

We can split the list before each second occurrence, if we write a function which always returns False but returns True when a second occurrence is compared to the element before it. That is the third check on that element (two checks on the first occurrence, plus the first check on the second occurrence). Hence, we use ++f[#]==3&. The nice thing is that this already returns False again on the second check of the second occurrence, such that I can return True for consecutive second occurrences, but still split between them. Likewise, this won't split after second occurrences, because the function already returns False again on the second check.

Now, the question wants us to also remove those second occurrences, so we drop the first element from each list, with Rest/@. But of course, we don't want to remove the very first element in the input, so we actually start off, by adding an element a to the beginning of the list with {a}~Join~#. a is an undefined variable, which Mathematica just treats as an unknown, so it won't affect any other values of f. This also ensures that the first actual element in the input gets its two checks like every other element.

\$\endgroup\$
2
  • \$\begingroup\$ That's pretty clever. You also actually don't need Boole in there. \$\endgroup\$
    – swish
    Commented Dec 23, 2014 at 15:30
  • \$\begingroup\$ @swish Ah, thanks for reminding me... I noticed that while on mobile, but wanted to test it before changing it. \$\endgroup\$ Commented Dec 23, 2014 at 15:31
5
\$\begingroup\$

Python, 148 bytes

def s(a):z=len(a);x=[-1]+sorted({[i for i in range(z)if a[i]==n][1]for n in a if a.count(n)>1})+[z];return[a[x[i]+1:x[i+1]]for i in range(len(x)-1)]

Pretty horrendous solution. There's got to be a better way...

Call with s([2, 1, 1, 1, 4, 5, 6]).

Ungolfed version

def split(array):
  indices = [-1]
  second_occurrences = set()

  for n in array:
      if array.count(n) > 1:
          occurrences = [i for i in range(len(array)) if array[i] == n]
          second_occurrences.add(occurrences[1])

  indices += sorted(second_occurrences)
  indices += [len(array)]

  return [array[indices[i]+1:indices[i+1]] for i in range(len(indices)-1)]
\$\endgroup\$
2
  • 1
    \$\begingroup\$ What the what… Could you edit in an un-golfed version? XD 148 characters is a very long line ;) \$\endgroup\$ Commented Dec 20, 2014 at 23:05
  • 1
    \$\begingroup\$ @SeanAllred I didn't want to post an explanation since I was sure I could do better, but since I'm having trouble I've posted the ungolfed version :P \$\endgroup\$
    – Sp3000
    Commented Dec 21, 2014 at 6:21
5
\$\begingroup\$

Haskell, 115 113 106 88

f?(x:s)|1<-f x=[]:x%f?s|a:b<-x%f?s=(x:a):b
f?x=[x]
(x%f)h=sum$f h:[1|x==h]
r s=(\_->0)?s

this stores the amount every element appeared so far as a function from elements to their respective amount, which is an interesting trick.

this works using %, a function that given a function f and an argument x returns a new function that returns f applied to it's argument if it is different than x, and 1 + f x otherwise.

for example, 3 % const 0 is a function which returns 0 for every argument except 3, for which it returns 1. update: fused the foldl to get a much smaller program.

\$\endgroup\$
1
  • \$\begingroup\$ This looks interesting. Could you provide an ungolfed version? \$\endgroup\$
    – radomaj
    Commented Jan 16, 2015 at 23:41
4
\$\begingroup\$

Ruby 66 demo

f=->a{c=Hash.new 0
r=[[]]
a.map{|e|2==(c[e]+=1)?r<<[]:r[-1]<<e}
r}

Ruby stabby lambda that takes an array as a parameter and returns an array of arrays.

\$\endgroup\$
4
\$\begingroup\$

Python: 100 byte

def g(l):
 i=j=0;o=[]
 for e in l:
  if l[:i].count(e)==1:o+=[l[j:i]];j=i+1
  i+=1
 return o+[l[j:]]

Straightforward solution. I iterate over the list, count how many times a character appeared before, and append the part since the last check to the output list.

\$\endgroup\$
3
\$\begingroup\$

Ruby, 66

f=->a{s=Hash.new 0
r=[[]]
a.map{|e|(s[e]+=1)==2?r<<[]:r[-1]<<e}
r}

Explanation

  • e is a Hash of occurrence counts for each element, r is an Array in which the result is stored.
  • Loop trough the input, increment the occurrence count for each element by 1.
    • If the occurrence count is 2, we need to split. Add an empty Array to the result.
    • Otherwise just add the element to the last Array in result.
\$\endgroup\$
4
  • 2
    \$\begingroup\$ Nice hat!! Oh wait. \$\endgroup\$
    – Optimizer
    Commented Dec 20, 2014 at 16:48
  • 4
    \$\begingroup\$ What an incredible coincidence! The answer I posted seconds before yours is almost identical. :) \$\endgroup\$ Commented Dec 20, 2014 at 16:49
  • \$\begingroup\$ Oh my, it's even 1 character shorter! \$\endgroup\$
    – britishtea
    Commented Dec 20, 2014 at 16:51
  • \$\begingroup\$ It's a saving you can easily apply to yours. I think it's awesome that we had the same idea at the same time. :D \$\endgroup\$ Commented Dec 20, 2014 at 16:51
3
\$\begingroup\$

CJam, 25 24 bytes

q~{_L+:L1$a/,3=S@?}%Sa/p

Takes input from STDIN like

[ 2 1 2 1 0 2 2 1 1 3 4 3]

and outputs like

[[2 1] "" [0 2 2 1 1 3 4] ""]

I am basically iterating over all elements of the array, one by one putting them into another array. Then I get the count of the current element in the other array. If its 2, I start another array from that location. This kind of random array starting can only be achieved in a stack based language.

Code expansion:

q~{_L+:L1$a/,3=S@?}%Sa/p
q~{               }%             "Evaluate the input array and map it on this block";
   _                             "Copy the current element in iteration";
    L+:L                         "Add the copy to an initially blank array L and update L";
        1$a/                     "Make another copy of the element and split L on it";
            ,3=                  "This checks if the splitted array is of length 3";
                                 "which indirectly means that L contains the element twice";
               S@?               "If the above is true, replace the element by space";
                    Sa/          "Split the final array on space. This final array contains";
                                 "second occurrence of every integer replaced by a space";
                       p         "Print the stringified version of the final nested array";

Try it online here

1 byte saved from Martin's tip on chat

\$\endgroup\$
3
\$\begingroup\$

Ruby, 64 bytes

s=->a{x=[];b=[[]];a.map{|e|x<<e;x.count(e)==2?b<<[]:b[-1]<<e};b}
\$\endgroup\$
3
\$\begingroup\$

Perl 5: 36

Not sure if this is acceptable as no actual splitting happens here.

#!perl -pa
$x{$_}++-1or$_=']['for@F;$_="[[@F]]"

Example:

$ perl spl.pl <<<"2 1 1 2 3 2 2 4 5 6 7 3 7 0 5"
[[2 1 ][ ][ 3 2 2 4 5 6 7 ][ ][ 0 ][]]
\$\endgroup\$
2
  • \$\begingroup\$ Totally acceptable. \$\endgroup\$
    – Optimizer
    Commented Dec 23, 2014 at 15:06
  • \$\begingroup\$ Nice answer. But standard practice, I think, is to count -pa as two extra bytes (because it "costs" only two bytes, since you can write it as -pae instead of -e). So that'd be 38, not 36. \$\endgroup\$
    – msh210
    Commented Jun 21, 2016 at 14:45
2
\$\begingroup\$

CJam, 28 bytes

Lq~{1$1$a/,3=S2$?@++}/-2%S/`

Takes input on STDIN like

[2 1 1 2 3 2 2 4 5 6 7 3 7 0 5]

and prints the output to STDOUT like

[[2 1] "" [3 2 2 4 5 6 7] "" [0] ""]

Note that empty strings and empty arrays are the same thing in CJam, and are displayed as "" by default (this is the native representation of empty arrays).

(I started working on this a bit before the challenge was posted, because we were discussing how difficult the challenge would be.)

Explanation

Basically, I'm duplicating each element in the array, unless it's the second occurrence, in which case I replace the first copy with a space. For golfing reasons, this modified array is constructed in reverse. So [2 1 1 2 3 2 3] becomes

[3 S 2 2 3 3 2 S 1 S 1 1 2 2]

Then I pick out every second element from the end, which is the original array, but with second occurrences replaced by spaces, i.e.

[2 1 S S 3 2 S]

Finally, I simply split the array on spaces. Here is a breakdown of the code:

L                            "Push empty array.";
 q~                          "Read STDIN an evaluate.";
   {                }/       "For each element of the input.";
    1$1$                     "Copy the array and the element.";
        a/                   "Split the array by that element.";
          ,3=                "Check that it's split into 3 parts.";
             S2$?            "If so, push a space, else, copy the current number.";
                 @++         "Pull up the array from the bottom and add both to the beginning.";
                      -2%    "Pick every second element from the end.";
                         S/  "Split on spaces.";
                           ` "Get the string representation.";
\$\endgroup\$
3
  • \$\begingroup\$ Since this is my own challenge, I am giving a chance first :P. I have a 25 byte Cjam solution with me. \$\endgroup\$
    – Optimizer
    Commented Dec 20, 2014 at 13:21
  • \$\begingroup\$ Doesn't display empty arrays correctly--obviously invalid! \$\endgroup\$
    – feersum
    Commented Dec 20, 2014 at 13:31
  • 1
    \$\begingroup\$ @feersum displaying empty arrays as "" is explicitly allowed in the first revision of the question. The current revision states "any convenient format ... usually native string represtation of arrays". \$\endgroup\$ Commented Dec 20, 2014 at 13:58
2
\$\begingroup\$

Unix tools, 100 bytes

grep -o '[-0-9]*'|awk '{print(++A[$0]-2)?$0:"] ["}'|paste -sd' '|sed -e '/]/s/.*/[\0]/' -e's//[\0]/'

Excepts the input via stdin. It basically just replaces every second occurrence with "] [". Does not work with empty strings, [] will give an empty string, which I think is a convenient representation of an empty array :)

\$\endgroup\$
2
  • \$\begingroup\$ Well, then the answer is not meeting the spec, right ? (about negative integers). Also, what about 11 ? will it get converted to 1][ ? \$\endgroup\$
    – Optimizer
    Commented Dec 20, 2014 at 14:27
  • \$\begingroup\$ It works well for 11, but you are right about negative numbers, fixed that, and it now also accepts singleton arrays. \$\endgroup\$
    – pgy
    Commented Dec 20, 2014 at 14:38
2
\$\begingroup\$

APL, 42 characters

{'(',')',⍨⍵[(2=+/¨(↑=↓)¨⌽¨,\⍵)/⍳⍴⍵]←⊂')('}

Example:

{'(',')',⍨⍵[(2=+/¨(↑=↓)¨⌽¨,\⍵)/⍳⍴⍵]←⊂')('}2 1 1 2 3 2 2 4 5 6 7 3 7 0 5

Output:

( 2 1  )(   )(  3 2 2 4 5 6 7  )(   )(  0  )(  )

Tested here.

If I must output a string that is interpreted exactly as the right structure in APL... 49 characters

{'1↓1(',',⍬)',⍨⍵[(2=+/¨(↑=↓)¨⌽¨,\⍵)/⍳⍴⍵]←⊂',⍬)('}
\$\endgroup\$
2
  • \$\begingroup\$ How is a nested list actually represented in APL ? Maybe you might not need to do string manipulation \$\endgroup\$
    – Optimizer
    Commented Dec 20, 2014 at 14:56
  • \$\begingroup\$ @Optimizer The outputed string is a valid list in an APL program. However it wouldn't be nested if there is only one list in it. Prepending a 1↓1 seemed to fix the problem, but that looks too weird. \$\endgroup\$
    – jimmy23013
    Commented Dec 20, 2014 at 15:15
2
\$\begingroup\$

Java, 223

This only works on Oracle or OpenJDK JRE, since I make use of this quirk in their implementation of quantifier and length check in look-behind to implement variable-length look-behind.

class W{public static void main(String a[]){System.out.print("["+new java.util.Scanner(System.in).nextLine().replaceAll(" *\\b(\\d+)\\b(?=(.*))(?<=^(?=(.*\\b\\1\\b){2}\\2).*)(?<!^(?=(.*\\b\\1\\b){3}\\2).*) *","] [")+"]");}}

Most of the work is done in the regex, which is shown below in raw form:

 *\b(\d+)\b(?=(.*))(?<=^(?=(.*\b\1\b){2}\2).*)(?<!^(?=(.*\b\1\b){3}\2).*) *

Before we look at the regex above, let us look at equivalent .NET regex, which is simpler, since it directly supports variable-length look-behind (.NET look-behind is most likely done by right-to-left matching mode):

 *\b(\d+)\b(?<=(.*\b\1\b){2})(?<!(.*\b\1\b){3}) *
  •  *\b(\d+)\b and  * at the end matches a number and the surrounding spaces (if any). The bound checks are to prevent partial number from being matched, since spaces on both sides are optional. It also captures the number to check whether it is the 2nd appearance in the array.

  • (?<=(.*\b\1\b){2}) checks that 2 instances of the number captured above can be found. (?<!(.*\b\1\b){3}) checks that no 3 instances of the number captured can be found. Both conditions combined asserts that there are only 2 instances of the number so far. The bound checks are there to make sure the whole number is tested.

Back to the Java version. To implement variable-length look behind, we transform

(?<=var-length-pattern)

to

(?<=^(?=.*var-length-pattern).*)

I am a bit hand-waving regarding the fact that . excludes line separators, but it can be fixed easily and I don't want to further complicate the syntax.

The look-ahead is always 0 in length, and the length check passes due to the implementation of * quantifier.

The ^ is not necessary to make it work, but it is there to make the failing case fails faster. Look-behind in Oracle/OpenJDK implementation is done by stepping back the minimum length of the pattern, then match, then rinse and repeat by incrementing the length until a match is found, or in the worst case, to the maximum length of the pattern. With ^, I make sure the prefix string is only matched once.

However, the look-ahead inside the look-behind is not limited by look-behind's right-boundary, so it can match all the way to the end of the string. In order to assert the boundary, I capture the rest of the string into another capturing group inside a look ahead, and use it to limit the reign of the variable length pattern.

(?=(.*))(?<=^(?=.*var-length-pattern\m).*)
   ^--^                              ^
   mth capturing group               m is the number of the capturing group marked

Since my pattern already starts with .*, I don't need to add another .* in front.

\$\endgroup\$
1
\$\begingroup\$

Perl 108

map{$e[$_]==1?do{push@a,[@b];@b=();}:push@b,$_;$e[$_]++}split" ";push@a,[@b];s/.*/Data::Dumper->Dump(\@a)/e;

In action:

perl -MData::Dumper -pe '
    $Data::Dumper::Terse = 1;
    $Data::Dumper::Indent = 0;
    @a=@b=@e=();
    map{$e[$_]==1?do{push@a,[@b];@b=();}:push@b,$_;$e[$_]++}split" ";
    push@a,[@b];
    s/.*/Data::Dumper->Dump(\@a)/e;
' <<<$'2 1 1 2 3 2 2 4 5 6 7 3 7 0 5\n2 1 1 1 4 5 6\n'"$(
    sed 's/./& /g;w/dev/stderr' <<< ${RANDOM}${RANDOM}${RANDOM}$'\n'${RANDOM}${RANDOM})"
2 4 4 7 7 2 9 8 8 4 6 0 1 8 
1 0 3 9 3 7 9 
[2,1][][3,2,2,4,5,6,7][][0][]
[2,1][1,4,5,6]
[2,4][7][][9,8][4,6,0,1,8]
[1,0,3,9][7][]

Nota: The two first lines $Data::... are there only for nicer presentation and third line @a=@b=@e=(); is there for making the tool working on multiple lines.

\$\endgroup\$
1
\$\begingroup\$

R, 76

y=scan();r=split(y,cumsum(ave(y,y,FUN=seq)==2));c(r[1],lapply(r[-1],"[",-1))

Output for the example: A list of five elements, including three empty vectors. (numeric(0)).

$`0`
[1] 2 1

$`1`
numeric(0)

$`2`
[1] 3 2 2 4 5 6 7

$`3`
numeric(0)

$`4`
[1] 0

$`5`
numeric(0)

By the way: The code generates a warning message that can be ignored.

\$\endgroup\$
1
\$\begingroup\$

awk 29

a[$1]++==1{print"-";next}1

This takes a bit of liberty with the input and output formats. Input "array" is vertical, one number per line. Output is also vertical, one number per line, with dashes separating arrays.

Input:

2
1
1
2
3
2
2
4
5
6
7
3
7
0
5

Output:

2
1
–
–
3
2
2
4
5
6
7
–
–
0
–
\$\endgroup\$
1
\$\begingroup\$

Pyth 30 32

This is my first time experimenting with Pyth. It's the same solution as in my Python solution.

VQIq/<QN@QN1~Y]:QZN=ZhN;+Y]>QZ

You can try it online: Pyth Compiler/Executor

E.g. The input

[2,1,1,2,3,2,2,4,5,6,7,3,7,0,5]

will print

[[2, 1], [], [3, 2, 2, 4, 5, 6, 7], [], [0], []]

Explanation:

                                 # Q = input(), Y = [], Z = 0
VQ                               # for loop: N iterates over the indices of Q
  I                              # if 
   q\<QN@QN1                     #    Q[N] appears exactly once in Q[:N]
            ~Y]:QZN              #         append the list [Q[Z:N]] to Y
                   =ZhN          #         and assign Z = N + 1
                       ;         # end if and for loop
                        +Y]>QZ   # print Y + [Q[Z:]]
\$\endgroup\$
2
  • \$\begingroup\$ Is there a better alternative for =Y+Y...? \$\endgroup\$
    – Jakube
    Commented Dec 22, 2014 at 19:59
  • \$\begingroup\$ this is - ~Y... \$\endgroup\$
    – Optimizer
    Commented Dec 22, 2014 at 20:17
1
\$\begingroup\$

Python 2, 84

l=[[]];p=[]
for x in input():p+=[x];b=p.count(x)==2;l+=[[]]*b;l[-1]+=[x][b:]
print l

The list l is the output so far. We iterate over the elements. If the current one is the second appearance, we start a new empty sublist; otherwise, we add it to the latest sublist. The list of elements seen so far is stored in p. Strangely, reconstructing the list seems shorter than slicing the input.

\$\endgroup\$
1
\$\begingroup\$

Pure bash 111 94

81 for only splitting:

for i;do [ "${b[i]}" == 7 ]&&c+=("${d# }") d=||d+=\ $i;b[i]+=7;done;c+=("${d# }")
declare -p c

The second line declare -p c just dumping the variable

Sample:

splitIntFunc() {
    local b c d i
    for i;do
        [ "${b[i]}" == 7 ]&&c+=("${d# }") d=||d+=\ $i
        b[i]+=7
      done
    c+=("${d# }")
    declare -p c
}

Nota: the line local b c d i is only required for running the function several times.

splitIntFunc 2 1 1 2 3 2 2 4 5 6 7 3 7 0 5
declare -a c='([0]="2 1" [1]="" [2]="3 2 2 4 5 6 7" [3]="" [4]="0" [5]="")'

splitIntFunc 2 1 1 1 4 5 6
declare -a c='([0]="2 1" [1]="1 4 5 6")'

splitIntFunc $(sed 's/./& /g;w/dev/stderr' <<<${RANDOM}${RANDOM}${RANDOM})
1 6 5 3 2 2 4 3 9 4 2 9 7 7 4 
declare -a c='([0]="1 6 5 3 2" [1]="4" [2]="9" [3]="2" [4]="7" [5]="4")'

splitIntFunc $(sed 's/./& /g;w/dev/stderr' <<<${RANDOM}${RANDOM}${RANDOM})
2 4 5 2 9 1 1 4 8 7 8 1 0 3 
declare -a c='([0]="2 4 5" [1]="9 1" [2]="" [3]="8 7" [4]="1 0 3")'

For sexiest presentation (+26)

splitIntFunc() {
    local b c d i
    for i;do
        [ "${b[i]}" == 7 ]&&c+=("${d# }") d=||d+=\ $i
        b[i]+=7
      done
    c+=("${d# }")
    printf -v l "(%s) " "${c[@]}"
    echo "<$l>"

Will render something like:

splitIntFunc 2 1 1 2 3 2 2 4 5 6 7 3 7 0 5
<(2 1) () (3 2 2 4 5 6 7) () (0) () >

splitIntFunc $(sed 's/./& /g;w/dev/stderr' <<<${RANDOM}${RANDOM}${RANDOM})
4 3 8 1 4 5 7 9 2 7 8 4 0 
<(4 3 8 1) (5 7 9 2) () (4 0) >

splitIntFunc $(sed 's/./& /g;w/dev/stderr' <<<${RANDOM}${RANDOM}${RANDOM})
3 1 3 0 2 5 3 6 6 9 2 5 5 
<(3 1) (0 2 5 3 6) (9) () (5) >

splitIntFunc $(sed 's/./& /g;w/dev/stderr' <<<${RANDOM}${RANDOM}${RANDOM})
2 2 2 9 1 9 5 0 2 2 7 6 5 4 
<(2) (2 9 1) (5 0 2 2 7 6) (4) >


}
\$\endgroup\$
0
\$\begingroup\$

Scala, 122111

Take character collection, print in form of [21][][3224567][][0][], 122111:

def s(a:Any*)=print((("[","")/:a){case((b,c),d)=>if(b.indexOf(d)==c.indexOf(d))(b+d,c)else(b+"][",c+d)}._1+"]")

...or take a character collection and return nested lists, 135129:

def s(a:Char*)=(("",List(List[Any]()))/:a){case((b,c),d)=>b+d->(if(b.count(d==)==1)List()::c else(c.head:+d)::c.tail)}._2.reverse

I'm sure there are some savings I could get, I have not looked too hard.

\$\endgroup\$
-1
\$\begingroup\$

Java: 563 bytes

note this uses Java 8, pre-JDK8 would be a few bytes longer due to the foreach.

import java.util.*;public class a{static String c(String[]b){List<String>d=new ArrayList<>(Arrays.asList(b));Set<String>e=new HashSet<>();Set<String>f=new HashSet<>();for(int i=0;i<Integer.MAX_VALUE;i++){String g;try{g=d.get(i);}catch(IndexOutOfBoundsException ex){break;}
if(e.contains(g)&&!f.contains(g)){d.remove(i);d.add(i,"]");d.add(i+1,"[");f.add(g);i++;}else{e.add(g);}}
d.add(0,"[[");d.add(d.size(),"]]");StringBuilder sb=new StringBuilder();d.forEach(sb::append);return sb.toString();}
public static void main(String[]args){System.out.println(c(args));}}
\$\endgroup\$
5
  • \$\begingroup\$ where else can I use lambda? looping till array's length is not correct because the list keeps expanding as you add more "]" and "[". \$\endgroup\$ Commented Dec 23, 2014 at 17:22
  • \$\begingroup\$ incrementing the length each time is just as lengthy as catching the exception, also I don't think it's possible in Java to change CEILING in (for i = 0; i < CEILING; i++). \$\endgroup\$ Commented Dec 23, 2014 at 17:28
  • \$\begingroup\$ Really ? \$\endgroup\$
    – Optimizer
    Commented Dec 23, 2014 at 17:35
  • \$\begingroup\$ hmm didn't know that, thanks for pointing out. \$\endgroup\$ Commented Dec 23, 2014 at 17:44
  • \$\begingroup\$ What about converting Integer.MAX_VALUE to 2147483647 ? It's the same value with less bytes. Also, IndexOutOfBoundsException can be shortened to Exception \$\endgroup\$
    – Charlie
    Commented Dec 26, 2014 at 9:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.