How to get the result of EXPECT_EXIT() in gtest?
I want to do something according to the results of EXPECT_EXIT. For example:
for(int i = 0; i < 1000; i++) {
for(int j = 0; j < 10; j++) {
auto &result = EXPECT_EXIT(Function(i, inputs[j]));
if (result) {
do something;
break; //jump out of the loop
}
}
}
From your comment:
But once it failed, I need record something and skip rest of the input
check for this function
Short answer:
To stop execution at first mismatch you need to use ASSERT version instead of EXPECT, in your case ASSERT_EXIT.
To output some extra data for failed check you can just use stream operator of check:
ASSERT_EXIT(Function(i, j), testing::ExitedWithCode(0), "") << "Some custom data: " << i << "; " << j;
If you want to do something more on fail - you can use ::testing::Test::HasFailure() function.
Long suggestion:
One of the properties of good unittest is simplicity. That implies absence of any loops or branches. Setup logic (if any) should be moved to fixtures. Also unittests must be executed in isolation.
By switching your test to parametric one you would cover that. Check this:
void Function(int i, int j)
{
if (j != 3)
exit(0);
}
class FunTest : public testing::TestWithParam<std::tuple<int, int>> { };
TEST_P(FunTest, Should_Exit)
{
const auto i = std::get<0>(GetParam());
const auto j = std::get<1>(GetParam());
EXPECT_EXIT(Function(i, j), testing::ExitedWithCode(0), "");
}
INSTANTIATE_TEST_SUITE_P(,
FunTest,
testing::Combine(
testing::Range(1, 20),
testing::Range(1, 10)),
[](const testing::TestParamInfo<std::tuple<int, int>>& info) -> std::string {
const auto i = std::get<0>(info.param);
const auto j = std::get<1>(info.param);
return std::to_string(i) + '_' + std::to_string(j);
});
This approach would help with your problem: you can stop execution by using --gtest_break_on_failure and you can control naming of test cases by implementing custom printer for specific TestParamInfo (lambda in example).
It would also guarantee isolation and provide certain level of simplicity (all complex stuff provided by framework, imho test code is minimalistic and simple).
Also this would allow execution of specific test using gtest_filter
(e.g. --gtest_filter=FunTest.Should_Exit/4_3).
I have a class like below.
class Student {
public Student(Set<String> seminars) {
this.seminar = seminars;
}
Set<String> seminar;
public Set<String> getSeminar()
{
return seminar;
}
}
And created a set of students like below.
List<Student> students = new ArrayList<Student>();
Set<String> seminars = new HashSet<String>();
seminars.add("SeminarA");
seminars.add("SeminarB");
seminars.add("SeminarC");
students.add(new Student(seminars)); //Student 1 - 3 seminars
students.add(new Student(seminars)); //Student 2 - 3 seminars
seminars = new HashSet<String>();
seminars.add("SeminarA");
seminars.add("SeminarB");
students.add(new Student(seminars)); //Student 3 - 2 seminars
seminars = new HashSet<String>();
students.add(new Student(seminars)); //Student 4 - 0 seminars
Now the question is "I'm trying to get the count of students who has atteneded maximus seminars" As you can see there are 2 students who has attended to 3(maximum) seminars, So I needed to get that count.
I achieved the same using 2 different statements using stream
OptionalInt max = students.stream()
.map(Student::getSeminar)
.mapToInt(Set::size)
.max();
long count = students.stream()
.map(Student::getSeminar)
.filter(size -> size.size() == max.getAsInt())
.count();
is there a way to achieve the same using one statement?
To solve this, please use the follwing code:
students.stream()
.map(Student::getSeminar)
.collect(Collectors.groupingBy(Set::size, Collectors.counting()));
Your output will be:
{0=1, 2=1, 3=2}
As you can see, there are two students that are going to the maximum number of seminars which is three.
First we changed all the students objects from the stream with the actual sets and then we used Collectors groupingBy() method to group the sets by size.
If you want to get only the number of the students, please use following code:
students.stream()
.map(Student::getSeminar)
.collect(Collectors.groupingBy(Set::size, Collectors.counting()))
.values().stream()
.max(Comparator.comparing(a->a))
.get();
Your output will be: 2.
In most practical situations, your approach of traversing the list twice is the best one. It is simple and the code is easy to understand. Fight the urge to conserve statements -- you don't get charged per semicolon!
However, there are some conceivable scenarios when the source data cannot be traversed twice. Perhaps it comes from some slow or once-only source like a network stream.
If you have such a situation, you might want to define a custom collector allMaxBy that collects all max elements into a downstream collector.
Then you would be able to write
long maxCount = students.stream()
.collect(allMaxBy(
comparingInt(s -> s.getSeminar().size()),
counting()
));
Here's an implementation for allMaxBy:
public static <T, A, R> Collector<T, ?, R> allMaxBy(Comparator<? super T> cmp, Collector<? super T, A, R> downstream) {
class AllMax {
T val;
A acc = null; // null means empty
void add(T t) {
int c = acc == null ? 1 : cmp.compare(t, val);
if (c > 0) {
val = t;
acc = downstream.supplier().get();
downstream.accumulator().accept(acc, t);
} else if (c == 0) {
downstream.accumulator().accept(acc, t);
}
}
AllMax merge(AllMax other) {
if (other.acc == null) {
return this;
} else if (this.acc == null) {
return other;
}
int c = cmp.compare(this.val, other.val);
if (c == 0) {
this.acc = downstream.combiner().apply(this.acc, other.acc);
}
return c >= 0 ? this : other;
}
R finish() {
return downstream.finisher().apply(acc);
}
}
return Collector.of(AllMax::new, AllMax::add, AllMax::merge, AllMax::finish);
}
This is ugly, but the following would work:
long count = students.stream()
.filter(s -> s.getSeminar().size() == students
.stream().mapToInt(a -> a.getSeminar().size())
.max().orElse(0))
.count();
Explanation: This streams the students list and filters the students so that only students with the maximum number of seminars (which is what the nested lambda is) remain and then takes the count of that stream.
Little modified #Alex's solution, to sort the keys while doing the grouping
TreeMap<Integer, Long> agg = students.stream()
.map(Student::getSeminar)
.collect(Collectors.groupingBy(Set::size, TreeMap::new, Collectors.counting()));
System.out.println(agg);
System.out.println(agg.lastEntry().getKey() + " - " + agg.lastEntry().getValue());
output
3 - 2
I have a List of a custom CallRecord objects
public class CallRecord {
private String callId;
private String aNum;
private String bNum;
private int seqNum;
private byte causeForOutput;
private int duration;
private RecordType recordType;
.
.
.
}
There are two logical conditions and the output of each is:
Highest seqNum, sum(duration)
Highest seqNum, sum(duration), highest causeForOutput
As per my understanding, Stream.max(), Collectors.summarizingInt() and so on will either require several iterations for the above result. I also came across a thread suggesting custom collector but I am unsure.
Below is the simple, pre-Java 8 code that is serving the purpose:
if (...) {
for (CallRecord currentRecord : completeCallRecords) {
highestSeqNum = currentRecord.getSeqNum() > highestSeqNum ? currentRecord.getSeqNum() : highestSeqNum;
sumOfDuration += currentRecord.getDuration();
}
} else {
byte highestCauseForOutput = 0;
for (CallRecord currentRecord : completeCallRecords) {
highestSeqNum = currentRecord.getSeqNum() > highestSeqNum ? currentRecord.getSeqNum() : highestSeqNum;
sumOfDuration += currentRecord.getDuration();
highestCauseForOutput = currentRecord.getCauseForOutput() > highestCauseForOutput ? currentRecord.getCauseForOutput() : highestCauseForOutput;
}
}
Your desire to do everything in a single iteration is irrational. You should strive for simplicity first, performance if necessary, but insisting on a single iteration is neither.
The performance depends on too many factors to make a prediction in advance. The process of iterating (over a plain collection) itself is not necessarily an expensive operation and may even benefit from a simpler loop body in a way that makes multiple traversals with a straight-forward operation more efficient than a single traversal trying to do everything at once. The only way to find out, is to measure using the actual operations.
Converting the operation to Stream operations may simplify the code, if you use it straight-forwardly, i.e.
int highestSeqNum=
completeCallRecords.stream().mapToInt(CallRecord::getSeqNum).max().orElse(-1);
int sumOfDuration=
completeCallRecords.stream().mapToInt(CallRecord::getDuration).sum();
if(!condition) {
byte highestCauseForOutput = (byte)
completeCallRecords.stream().mapToInt(CallRecord::getCauseForOutput).max().orElse(0);
}
If you still feel uncomfortable with the fact that there are multiple iterations, you could try to write a custom collector performing all operations at once, but the result will not be better than your loop, neither in terms of readability nor efficiency.
Still, I’d prefer avoiding code duplication over trying to do everything in one loop, i.e.
for(CallRecord currentRecord : completeCallRecords) {
int nextSeqNum = currentRecord.getSeqNum();
highestSeqNum = nextSeqNum > highestSeqNum ? nextSeqNum : highestSeqNum;
sumOfDuration += currentRecord.getDuration();
}
if(!condition) {
byte highestCauseForOutput = 0;
for(CallRecord currentRecord : completeCallRecords) {
byte next = currentRecord.getCauseForOutput();
highestCauseForOutput = next > highestCauseForOutput? next: highestCauseForOutput;
}
}
With Java-8 you can resolved it with a Collector with no redudant iteration.
Normally, we can use the factory methods from Collectors, but in your case you need to implement a custom Collector, that reduces a Stream<CallRecord> to an instance of SummarizingCallRecord which cotains the attributes you require.
Mutable accumulation/result type:
class SummarizingCallRecord {
private int highestSeqNum = 0;
private int sumDuration = 0;
// getters/setters ...
}
Custom collector:
BiConsumer<SummarizingCallRecord, CallRecord> myAccumulator = (a, callRecord) -> {
a.setHighestSeqNum(Math.max(a.getHighestSeqNum(), callRecord.getSeqNum()));
a.setSumDuration(a.getSumDuration() + callRecord.getDuration());
};
BinaryOperator<SummarizingCallRecord> myCombiner = (a1, a2) -> {
a1.setHighestSeqNum(Math.max(a1.getHighestSeqNum(), a2.getHighestSeqNum()));
a1.setSumDuration(a1.getSumDuration() + a2.getSumDuration());
return a1;
};
Collector<CallRecord, SummarizingCallRecord, SummarizingCallRecord> myCollector =
Collector.of(
() -> new SummarizinCallRecord(),
myAccumulator,
myCombiner,
// Collector.Characteristics.CONCURRENT/IDENTITY_FINISH/UNORDERED
);
Execution example:
List<CallRecord> callRecords = new ArrayList<>();
callRecords.add(new CallRecord(1, 100));
callRecords.add(new CallRecord(5, 50));
callRecords.add(new CallRecord(3, 1000));
SummarizingCallRecord summarizingCallRecord = callRecords.stream()
.collect(myCollector);
// Result:
// summarizingCallRecord.highestSeqNum = 5
// summarizingCallRecord.sumDuration = 1150
You don't need and should not implement the logic by Stream API because the tradition for-loop is simple enough and the Java 8 Stream API can't make it simpler:
int highestSeqNum = 0;
long sumOfDuration = 0;
byte highestCauseForOutput = 0; // just get it even if it may not be used. there is no performance hurt.
for(CallRecord currentRecord : completeCallRecords) {
highestSeqNum = Math.max(highestSeqNum, currentRecord.getSeqNum());
sumOfDuration += currentRecord.getDuration();
highestCauseForOutput = Math.max(highestCauseForOutput, currentRecord.getCauseForOutput());
}
// Do something with or without highestCauseForOutput.
I can't seem to find a great way to express the following in Xtend without resorting to a while loop:
for(int i = 0; i < 3; i++){
println("row ");
}
println("your boat");
So, I guess my question has two parts:
Is there a better way to do the above? I didn't see anything promising in their documenation
A large portion of the features the language has are just Xtend library extensions (and they're great!). Is there range() functionality à la Python that I don't know about?
I ended up rolling my own and got something like the following:
class LanguageUtil {
def static Iterable<Integer> range(int stop) {
range(0, stop)
}
def static Iterable<Integer> range(int start, int stop) {
new RangeIterable(start, stop, 1)
}
def static Iterable<Integer> range(int start, int stop, int step) {
new RangeIterable(start, stop, step)
}
}
// implements Iterator and Iterable which is bad form.
class RangeIterable implements Iterator<Integer>, Iterable<Integer> {
val int start
val int stop
val int step
var int current
new(int start, int stop, int step) {
this.start = start;
this.stop = stop;
this.step = step
this.current = start
}
override hasNext() {
current < stop
}
override next() {
val ret = current
current = current + step
ret
}
override remove() {
throw new UnsupportedOperationException("Auto-generated function stub")
}
/**
* This is bad form. We could return a
* new RangeIterable here, but that seems worse.
*/
override iterator() {
this
}
}
The exact replacement for
for(int i = 0; i < 3; i++){
println("row ");
}
is
for (i : 0 ..< 3) {
println("row ")
}
Notice the exclusive range operator: ..<
Also you can doing it more idiomatically with
(1..3).forEach[println("row")]
Very new to Xtend but man it makes programming on the jvm awesome.
To me a range-based forEach implies the range is somehow meaningful. For looping a specific number of times with no iteration variable, I find Ruby's times loop expresses the intent more clearly:
3.times [|println("row")]
Sadly it's not a part of IntegerExtensions, but the implementation is trivial:
def static times(int iterations, Runnable runnable) {
if (iterations < 0) throw new IllegalArgumentException(
'''Can't iterate negative («iterations») times.''')
for (i: 0 ..< iterations) runnable.run()
}
Heh, I found the answer a little while later:
for(i: 1..3) {
println("row ")
}
Since Xtend 2.6, we also support the "traditional" for-loop, just like in Java.
There is actually a version of forEach() that accepts a lambda with two parameters.
It is useful if you need to access the iteration index within the loop.
(10..12).forEach[ x, i | println('''element=«x» index=«i»''')]
prints:
element=10 index=0
element=11 index=1
element=12 index=2
What is the best way to join a list of strings into a combined delimited string. I'm mainly concerned about when to stop adding the delimiter. I'll use C# for my examples but I would like this to be language agnostic.
EDIT: I have not used StringBuilder to make the code slightly simpler.
Use a For Loop
for(int i=0; i < list.Length; i++)
{
result += list[i];
if(i != list.Length - 1)
result += delimiter;
}
Use a For Loop setting the first item previously
result = list[0];
for(int i = 1; i < list.Length; i++)
result += delimiter + list[i];
These won't work for an IEnumerable where you don't know the length of the list beforehand so
Using a foreach loop
bool first = true;
foreach(string item in list)
{
if(!first)
result += delimiter;
result += item;
first = false;
}
Variation on a foreach loop
From Jon's solution
StringBuilder builder = new StringBuilder();
string delimiter = "";
foreach (string item in list)
{
builder.Append(delimiter);
builder.Append(item);
delimiter = ",";
}
return builder.ToString();
Using an Iterator
Again from Jon
using (IEnumerator<string> iterator = list.GetEnumerator())
{
if (!iterator.MoveNext())
return "";
StringBuilder builder = new StringBuilder(iterator.Current);
while (iterator.MoveNext())
{
builder.Append(delimiter);
builder.Append(iterator.Current);
}
return builder.ToString();
}
What other algorithms are there?
It's impossible to give a truly language-agnostic answer here as different languages and platforms handle strings differently, and provide different levels of built-in support for joining lists of strings. You could take pretty much identical code in two different languages, and it would be great in one and awful in another.
In C#, you could use:
StringBuilder builder = new StringBuilder();
string delimiter = "";
foreach (string item in list)
{
builder.Append(delimiter);
builder.Append(item);
delimiter = ",";
}
return builder.ToString();
This will prepend a comma on all but the first item. Similar code would be good in Java too.
EDIT: Here's an alternative, a bit like Ian's later answer but working on a general IEnumerable<string>.
// Change to IEnumerator for the non-generic IEnumerable
using (IEnumerator<string> iterator = list.GetEnumerator())
{
if (!iterator.MoveNext())
{
return "";
}
StringBuilder builder = new StringBuilder(iterator.Current);
while (iterator.MoveNext())
{
builder.Append(delimiter);
builder.Append(iterator.Current);
}
return builder.ToString();
}
EDIT nearly 5 years after the original answer...
In .NET 4, string.Join was overloaded pretty significantly. There's an overload taking IEnumerable<T> which automatically calls ToString, and there's an overload for IEnumerable<string>. So you don't need the code above any more... for .NET, anyway.
In .NET, you can use the String.Join method:
string concatenated = String.Join(",", list.ToArray());
Using .NET Reflector, we can find out how it does it:
public static unsafe string Join(string separator, string[] value, int startIndex, int count)
{
if (separator == null)
{
separator = Empty;
}
if (value == null)
{
throw new ArgumentNullException("value");
}
if (startIndex < 0)
{
throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
}
if (count < 0)
{
throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
}
if (startIndex > (value.Length - count))
{
throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
}
if (count == 0)
{
return Empty;
}
int length = 0;
int num2 = (startIndex + count) - 1;
for (int i = startIndex; i <= num2; i++)
{
if (value[i] != null)
{
length += value[i].Length;
}
}
length += (count - 1) * separator.Length;
if ((length < 0) || ((length + 1) < 0))
{
throw new OutOfMemoryException();
}
if (length == 0)
{
return Empty;
}
string str = FastAllocateString(length);
fixed (char* chRef = &str.m_firstChar)
{
UnSafeCharBuffer buffer = new UnSafeCharBuffer(chRef, length);
buffer.AppendString(value[startIndex]);
for (int j = startIndex + 1; j <= num2; j++)
{
buffer.AppendString(separator);
buffer.AppendString(value[j]);
}
}
return str;
}
There's little reason to make it language-agnostic when some languages provide support for this in one line, e.g., Python's
",".join(sequence)
See the join documentation for more info.
For python be sure you have a list of strings, else ','.join(x) will fail.
For a safe method using 2.5+
delimiter = '","'
delimiter.join(str(a) if a else '' for a in list_object)
The "str(a) if a else ''" is good for None types otherwise str() ends up making then 'None' which isn't nice ;)
In PHP's implode():
$string = implode($delim, $array);
I'd always add the delimeter and then remove it at the end if necessary. This way, you're not executing an if statement for every iteration of the loop when you only care about doing the work once.
StringBuilder sb = new StringBuilder();
foreach(string item in list){
sb.Append(item);
sb.Append(delimeter);
}
if (list.Count > 0) {
sb.Remove(sb.Length - delimter.Length, delimeter.Length)
}
I would express this recursively.
Check if the number of string arguments is 1. If it is, return it.
Otherwise recurse, but combine the first two arguments with the delimiter between them.
Example in Common Lisp:
(defun join (delimiter &rest strings)
(if (null (rest strings))
(first strings)
(apply #'join
delimiter
(concatenate 'string
(first strings)
delimiter
(second strings))
(cddr strings))))
The more idiomatic way is to use reduce, but this expands to almost exactly the same instructions as the above:
(defun join (delimiter &rest strings)
(reduce (lambda (a b)
(concatenate 'string a delimiter b))
strings))
List<string> aaa = new List<string>{ "aaa", "bbb", "ccc" };
string mm = ";";
return aaa.Aggregate((a, b) => a + mm + b);
and you get
aaa;bbb;ccc
lambda is pretty handy
In C# you can just use String.Join(separator,string_list)
The problem is that computer languages rarely have string booleans, that is, methods that are of type string that do anything useful. SQL Server at least has is[not]null and nullif, which when combined solve the delimiter problem, by the way: isnotnull(nullif(columnvalue, ""),"," + columnvalue))
The problem is that in languages there are booleans, and there are strings, and never the twain shall meet except in ugly coding forms, e.g.
concatstring = string1 + "," + string2;
if (fubar)
concatstring += string3
concatstring += string4 etc
I've tried mightily to avoid all this ugliness, playing comma games and concatenating with joins, but I'm still left with some of it, including SQL Server errors when I've missed one of the commas and a variable is empty.
Jonathan
Since you tagged this language agnostic,
This is how you would do it in python
# delimiter can be multichar like "| trlalala |"
delimiter = ";"
# sequence can be any list, or iterator/generator that returns list of strings
result = delimiter.join(sequence)
#result will NOT have ending delimiter
Edit: I see I got beat to the answer by several people. Sorry for dupication
I thint the best way to do something like that is (I'll use pseudo-code, so we'll make it truly language agnostic):
function concat(<array> list, <boolean> strict):
for i in list:
if the length of i is zero and strict is false:
continue;
if i is not the first element:
result = result + separator;
result = result + i;
return result;
the second argument to concat(), strict, is a flag to know if eventual empty strings have to be considered in concatenation or not.
I'm used to not consider appending a final separator; on the other hand, if strict is false the resulting string could be free of stuff like "A,B,,,F", provided the separator is a comma, but would instead present as "A,B,F".
that's how python solves the problem:
','.join(list_of_strings)
I've never could understand the need for 'algorithms' in trivial cases though
This is a Working solution in C#, in Java, you can use similar for each on iterator.
string result = string.Empty;
// use stringbuilder at some stage.
foreach (string item in list)
result += "," + item ;
result = result.Substring(1);
// output: "item,item,item"
If using .NET, you might want to use extension method so that you can do
list.ToString(",")
For details, check out Separator Delimited ToString for Array, List, Dictionary, Generic IEnumerable
// contains extension methods, it must be a static class.
public static class ExtensionMethod
{
// apply this extension to any generic IEnumerable object.
public static string ToString<T>(this IEnumerable<T> source,
string separator)
{
if (source == null)
throw new ArgumentException("source can not be null.");
if (string.IsNullOrEmpty(separator))
throw new ArgumentException("separator can not be null or empty.");
// A LINQ query to call ToString on each elements
// and constructs a string array.
string[] array =
(from s in source
select s.ToString()
).ToArray();
// utilise builtin string.Join to concate elements with
// customizable separator.
return string.Join(separator, array);
}
}
EDIT:For performance reasons, replace the concatenation code with string builder solution that mentioned within this thread.
Seen the Python answer like 3 times, but no Ruby?!?!?
the first part of the code declares a new array. Then you can just call the .join() method and pass the delimiter and it will return a string with the delimiter in the middle. I believe the join method calls the .to_s method on each item before it concatenates.
["ID", "Description", "Active"].join(",")
>> "ID, Description, Active"
this can be very useful when combining meta-programming with with database interaction.
does anyone know if c# has something similar to this syntax sugar?
In Java 8 we can use:
List<String> list = Arrays.asList(new String[] { "a", "b", "c" });
System.out.println(String.join(",", list)); //Output: a,b,c
To have a prefix and suffix we can do
StringJoiner joiner = new StringJoiner(",", "{", "}");
list.forEach(x -> joiner.add(x));
System.out.println(joiner.toString()); //Output: {a,b,c}
Prior to Java 8 you can do like Jon's answer
StringBuilder sb = new StringBuilder(prefix);
boolean and = false;
for (E e : iterable) {
if (and) {
sb.append(delimiter);
}
sb.append(e);
and = true;
}
sb.append(suffix);
In .NET, I would use the String.join method if possible, which allows you to specify a separator and a string array. A list can be converted to an array with ToArray, but I don't know what the performance hit of that would be.
The three algorithms that you mention are what I would use (I like the second because it does not have an if statement in it, but if the length is not known I would use the third because it does not duplicate the code). The second will only work if the list is not empty, so that might take another if statement.
A fourth variant might be to put a seperator in front of every element that is concatenated and then remove the first separator from the result.
If you do concatenate strings in a loop, note that for non trivial cases the use of a stringbuilder will vastly outperform repeated string concatenations.
You could write your own method AppendTostring(string, delimiter) that appends the delimiter if and only if the string is not empty. Then you just call that method in any loop without having to worry when to append and when not to append.
Edit: better yet of course to use some kind of StringBuffer in the method if available.
string result = "";
foreach(string item in list)
{
result += delimiter + item;
}
result = result.Substring(1);
Edit: Of course, you wouldn't use this or any one of your algorithms to concatenate strings. With C#/.NET, you'd probably use a StringBuilder:
StringBuilder sb = new StringBuilder();
foreach(string item in list)
{
sb.Append(delimiter);
sb.Append(item);
}
string result = sb.ToString(1, sb.Length-1);
And a variation of this solution:
StringBuilder sb = new StringBuilder(list[0]);
for (int i=1; i<list.Count; i++)
{
sb.Append(delimiter);
sb.Append(list[i]);
}
string result = sb.ToString();
Both solutions do not include any error checks.
From http://dogsblog.softwarehouse.co.zw/post/2009/02/11/IEnumerable-to-Comma-Separated-List-(and-more).aspx
A pet hate of mine when developing is making a list of comma separated ids, it is SO simple but always has ugly code.... Common solutions are to loop through and put a comma after each item then remove the last character, or to have an if statement to check if you at the begining or end of the list. Below is a solution you can use on any IEnumberable ie a List, Array etc. It is also the most efficient way I can think of doing it as it relies on assignment which is better than editing a string or using an if.
public static class StringExtensions
{
public static string Splice<T>(IEnumerable<T> args, string delimiter)
{
StringBuilder sb = new StringBuilder();
string d = "";
foreach (T t in args)
{
sb.Append(d);
sb.Append(t.ToString());
d = delimiter;
}
return sb.ToString();
}
}
Now it can be used with any IEnumerable eg.
StringExtensions.Splice(billingTransactions.Select(t => t.id), ",")
to give us 31,32,35
For java a very complete answer has been given in this question or this question.
That is use StringUtils.join in Apache Commons
String result = StringUtils.join(list, ", ");
In Clojure, you could just use clojure.contrib.str-utils/str-join:
(str-join ", " list)
But for the actual algorithm:
(reduce (fn [res cur] (str res ", " cur)) list)
Groovy also has a String Object.join(String) method.
Java (from Jon's solution):
StringBuilder sb = new StringBuilder();
String delimiter = "";
for (String item : items) {
sb.append(delimiter).append(item);
delimeter = ", ";
}
return sb.toString();
Here is my humble try;
public static string JoinWithDelimiter(List<string> words, string delimiter){
string joinedString = "";
if (words.Count() > 0)
{
joinedString = words[0] + delimiter;
for (var i = 0; i < words.Count(); i++){
if (i > 0 && i < words.Count()){
if (joinedString.Length > 0)
{
joinedString += delimiter + words[i] + delimiter;
} else {
joinedString += words[i] + delimiter;
}
}
}
}
return joinedString;
}
Usage;
List<string> words = new List<string>(){"my", "name", "is", "Hari"};
Console.WriteLine(JoinWithDelimiter(words, " "));