I have written a quick piece of Java code to create some CSV data. The code simply outputs all of the permutations of specified lists of values and gives each row a unique value.
I want to know if these is a simple way to remove all of the nested for-loops and do this task more elegantly, whilst retaining simplicity.
The value of the variable "dataValue" is unimportant - I just require unique values for each row.
I am aware that there are other ways to create simple CSV data outside of Java (e.g. Excel) - I am interested in if this code can be improved.
public class DataCreator {
public static void main(String[] args) {
String[] dataDomains = {"DD1", "DD2", "DD3", "DD4"};
String[] referenceCodes = {"1A", "1B", "1C", "1D", "1E", "1F", "1G", "1H", "1J", "1K", "1L", "1M", "1N", "1O", "1P", "1Q"};
String[] indicators = {"AB1", "ZZ2", "FAQWE1", "1234", "_Z"};
String[] freqs = {"D"};
String[] timePeriods =
{
"2001-01-01", "2001-01-02", "2001-01-03", "2001-01-04", "2001-01-05", "2001-01-06", "2001-01-07", "2001-01-08", "2001-01-09", "2001-01-10", "2001-01-11", "2001-01-12", "2001-01-13", "2001-01-14", "2001-01-15", "2001-01-16", "2001-01-17", "2001-01-18", "2001-01-19", "2001-01-20", "2001-01-21", "2001-01-22", "2001-01-23", "2001-01-24", "2001-01-25", "2001-01-26", "2001-01-27", "2001-01-28", "2001-01-29", "2001-01-30", "2001-01-31",
"2001-02-01", "2001-02-02", "2001-02-03", "2001-02-04", "2001-02-05", "2001-02-06", "2001-02-07", "2001-02-08", "2001-02-09", "2001-02-10", "2001-02-11", "2001-02-12", "2001-02-13", "2001-02-14", "2001-02-15", "2001-02-16", "2001-02-17", "2001-02-18", "2001-02-19", "2001-02-20", "2001-02-21", "2001-02-22", "2001-02-23", "2001-02-24", "2001-02-25", "2001-02-26", "2001-02-27", "2001-02-28",
"2001-03-01", "2001-03-02", "2001-03-03", "2001-03-04", "2001-03-05", "2001-03-06", "2001-03-07", "2001-03-08", "2001-03-09", "2001-03-10", "2001-03-11", "2001-03-12", "2001-03-13", "2001-03-14", "2001-03-15", "2001-03-16", "2001-03-17", "2001-03-18", "2001-03-19", "2001-03-20", "2001-03-21", "2001-03-22", "2001-03-23", "2001-03-24", "2001-03-25", "2001-03-26", "2001-03-27", "2001-03-28", "2001-03-29", "2001-03-30", "2001-03-31"
};
int dataValue = 1;
for (String dataDomain: dataDomains) {
for (String refCode : referenceCodes) {
for (String indicator : indicators) {
for (String freq : freqs) {
for (String tp: timePeriods) {
System.out.println(
dataDomain + ", " +
refCode + ", " +
indicator + ", " +
freq + ", " +
tp + ", " +
dataValue
);
dataValue++;
}
}
}
}
}
}
}
Example output:
DD1, 1A, AB1, D, 2001年01月01日, 1
DD1, 1A, AB1, D, 2001年01月02日, 2
DD1, 1A, AB1, D, 2001年01月03日, 3
DD1, 1A, AB1, D, 2001年01月04日, 4
DD1, 1A, AB1, D, 2001年01月05日, 5
DD1, 1A, AB1, D, 2001年01月06日, 6
...
1 Answer 1
I want to know if these is a simple way to remove all of the nested for-loops and do this task more elegantly, whilst retaining simplicity.
Yes, for some definition of simplicity. Consider
public class DataCreator implements Iterable<String> {
private final List<List<String>> parts;
private final List<String> lines = new ArrayList<>();
private final String SEPARATOR;
private DataCreator(List<List<String>> parts, String separator) {
this.parts = parts;
this.SEPARATOR = separator;
}
private void joinParts(int index, String line) {
if (index >= parts.size()) {
lines.add(line + lines.size());
return;
}
for (String part : parts.get(index++)) {
joinParts(index, line + part + SEPARATOR);
}
}
@Override
public Iterator<String> iterator() {
return lines.iterator();
}
public static DataCreator create(List<List<String>> parts, String separator) {
DataCreator creator = new DataCreator(parts, separator);
creator.joinParts(0, new String());
return creator;
}
public static void main(String[] args) {
String[] timePeriods =
{
"2001-01-01", "2001-01-02", "2001-01-03", "2001-01-04", "2001-01-05",
"2001-01-06", "2001-01-07", "2001-01-08", "2001-01-09", "2001-01-10", "2001-01-11",
"2001-01-12", "2001-01-13", "2001-01-14", "2001-01-15", "2001-01-16", "2001-01-17",
"2001-01-18", "2001-01-19", "2001-01-20", "2001-01-21", "2001-01-22", "2001-01-23",
"2001-01-24", "2001-01-25", "2001-01-26", "2001-01-27", "2001-01-28", "2001-01-29",
"2001-01-30", "2001-01-31",
"2001-02-01", "2001-02-02", "2001-02-03", "2001-02-04", "2001-02-05",
"2001-02-06", "2001-02-07", "2001-02-08", "2001-02-09", "2001-02-10", "2001-02-11",
"2001-02-12", "2001-02-13", "2001-02-14", "2001-02-15", "2001-02-16", "2001-02-17",
"2001-02-18", "2001-02-19", "2001-02-20", "2001-02-21", "2001-02-22", "2001-02-23",
"2001-02-24", "2001-02-25", "2001-02-26", "2001-02-27", "2001-02-28",
"2001-03-01", "2001-03-02", "2001-03-03", "2001-03-04", "2001-03-05",
"2001-03-06", "2001-03-07", "2001-03-08", "2001-03-09", "2001-03-10", "2001-03-11",
"2001-03-12", "2001-03-13", "2001-03-14", "2001-03-15", "2001-03-16", "2001-03-17",
"2001-03-18", "2001-03-19", "2001-03-20", "2001-03-21", "2001-03-22", "2001-03-23",
"2001-03-24", "2001-03-25", "2001-03-26", "2001-03-27", "2001-03-28", "2001-03-29",
"2001-03-30", "2001-03-31"
};
List<List<String>> parts = new ArrayList<>();
parts.add(Arrays.asList("DD1", "DD2", "DD3", "DD4"));
parts.add(Arrays.asList("1A", "1B", "1C", "1D", "1E", "1F", "1G", "1H",
"1J", "1K", "1L", "1M", "1N", "1O", "1P", "1Q"));
parts.add(Arrays.asList("AB1", "ZZ2", "FAQWE1", "1234", "_Z"));
parts.add(Arrays.asList("D"));
parts.add(Arrays.asList(timePeriods));
for (String line : DataCreator.create(parts, ", ")) {
System.out.println(line);
}
}
}
This is slightly more complicated, but it uses it for making the code more generic and reusable.
I used the factory method (create
) because I don't like doing complicated work in the constructor. This leaves the code more flexible for later modification.
Advantages over the original:
- Easy to add or remove columns. Just add or delete the appropriate
parts.add
line. - Reusable. Capable of doing things other than immediate display.
- Easy to use. Because it implements
Iterable
, you can just throw it into afor
loop and use it. - Divided into methods.
- Defines
SEPARATOR
at construction time rather than hardcoding it.
Downsides retained include that you have to edit code to change the format of the strings. For example, if you wanted the row number to be in the first column instead of the last, you would have to modify the code.
I left main
inside of DataCreator
for simplicity's sake. Best practices would suggest putting it in its own class so that DataCreator
would be more reusable.
A possible future improvement would be to generate the timePeriods
with a method. More complicated the first time that you write it, but easier to use in the future.
-
\$\begingroup\$ Thank you! This is the sort of answer I was looking for and thanks for the explanations of advantages and downsides. \$\endgroup\$Phil– Phil2017年05月22日 13:26:01 +00:00Commented May 22, 2017 at 13:26