Am I the only one who always falls into the `"".sp...
# getting-started
d
Am I the only one who always falls into the
"".split(",").size == 1
trap? ๐Ÿ˜„
j
I'm not sure I understand which trap you mean. What would you expect to happen?
v
Probably he expects size to be 0. If so, for me tha answer is "no"
d
Yes, I would expect that split on an empty string returns the empty list. If the answer for you is "no", could you please share your reasoning behind that?
v
Same why
"foo,".split(",").size == 2
๐Ÿ‘ 2
j
Ah I see. Then no this doesn't surprise me. The reasoning: you have a string and want a list based on the
,
separator. Every element around
,
separators must be accounted for, empty strings are not special. When there is no separator, I wouldn't expect
"a"
to behave differently from
""
, I get one element which is the whole string.
๐Ÿ‘๐Ÿฝ 1
I guess this boils down to the fact that empty strings aren't special
v
It splits around the separator and gives all the split tokens.
"foo,".split(",")
results in
"foo"
and
""
.
"foo,,bar".split(",")
results in
"foo"
,
""
, and
"bar"
.
",".split(",")
results in
""
and
""
.
"".split(",")
results in
""
.
d
Ok. So the rule could be formulated as "the resulting list has the size equal to the number of separator occurecnces plus one"?
v
Yes
j
Yes, and the nice thing is that it holds true, regardless of the emptiness of some segments/elements
Also, it has the nice consequence to play well with concatenation: no surprises if you do
(s1 + "," + s2).split(",")
, or if you split
s1
and
s2
separately
k
Be careful if you're used to Java. Java's
split
behaves differently.
v
No it does not
Or what do you mean?
k
In Java,
"one,".split(",")
returns one element.
v
Oh, right, there is this one strange special case with trailing delimiter unless you specify limit of
-1
, sorry, forgot about that.
d
Well, it doesn't play well with
joinToString
๐Ÿ˜ž
Copy code
listOf<Int>().joinToString(",").split(",").size == 1
Intuitively, one would expect that joinToString and split are inverse to each other.
j
Fair enough, although I would argue that
joinToString()
is not injective (joining an empty list yields the same as joining a list of one element mapped to the empty string), so there is no way
split()
could be its inverse
v
Yep,
listOf<String>().joinToString(",").split(",") == listOf("").joinToString(",").split(",")
They are not made to be inverse of each other, so they are not ๐Ÿ™‚
d
Yes, that's true for list of strings but that is kind of an edge case. I don't think you can make the same argument for list of ints for example.
v
But
joinToString
is operating on list of strings. If you don't give an explicit transform to make string out of it, it calls
toString()
The output of your
split
is not a list of ints, but a list of strings
Another hint, that they are not "inverse"
d
Yeah, surely they are not inverse in the strict sense. My point is that looking at this code
Copy code
fun intListToCommaString(list: List<Int>) = list.joinToString(",")

fun commaStringToIntList(string: String) = string.split(",").map { it.toInt() }
I would think that those two functions are inverse. And indeed they are for every valid input except for the empty list case, which is kind of strange IMO. Or at least not obvious.
I had this exact code in my JPA entity attribute converter and the behaviour around the empty list surprised me. I understand, though, that "fixing" this particular case (i.e. making the split behaviour obvious wrt joinToString) might make other cases non-obvious.
๐Ÿ‘Œ 1