Process multiple csv lines with java - java

I have a file which I write a csv values each in a new line into. The result looks smth like that:
Hello;kind;world
Mister;John;Doe
and so on. I also have a class with a constructor taking each partial value, e.g. John as a parameter:
public MyClass(String first, String second, String third) {}
As a result I need a Collection<MyClass>. While processing I iterate over each csv line and then in an inner for loop over the particular line values after splitting it with a ; like that:
Collection<String> csvLines = Files.readAllLines(pathToMyFile);
for (String csvLine : csvLines) {
String[] csvLineSplitted = csvLine.split(";");
for (int i = 0; i < csvLineSplitted.length; i++) {
String value = scvLineSPlitted[i]; //This can be the above mentioned value, e.g. 'John'
}
}
How can I create an object of type MyClass with each of this particular parameter and then store it in the Collection<MyCLass> result?

Just define a class:
public class MyClass {
private String param1;
private String param2;
public MyClass(String param1, String param2) {
this.param1 = param1;
this.param2 = param2;
}
// getters and setters
}
And then use that class when you iterate over your CSV data:
Collection<String> csvLines = Files.readAllLines(pathToMyFile);
List<MyClass> list = new ArrayList<>();
for (String csvLine : csvLines) {
String[] csvLineSplitted = csvLine.split(";");
MyClass node = new MyClass(csvLineSplitted[0], csvLineSplitted[1]);
list.add(node);
}
Note that I am assuming here that your data only has two columns. If the actual data has several columns, then your approach of iterating in a for loop makes more sense.

You can achieve this with Streams too:
private class MyClass {
private String first;
private String second;
MyClass(String first, String second) {
this.first = first;
this.second = second;
}
#Override
public String toString() {
return "MyClass [first=" + first + ", second=" + second + "]";
}
}
List<MyClass> list = Files.lines(path)
.map(line -> line.split(";"))
.map(splittedLine -> new MyClass(splittedLine[0], splittedLine[1]))
.collect(Collectors.toList());
System.out.println(list);
If you got more than two columns just modify the second map operator to fit your requirements

Related

Convert String returning method to List<String> returning method in Java

I want the following method to return List of type String instead of String return type, The other method from which following "build" being called will receive List of type String (not StringBuilder)
public String build(String Uri, String Id) {
StringBuilder DocUri = new StringBuilder();
if (Uri.contains("newString")) {
DocUri.append("user-profile1/users/").append(Id).append("/user.xml");
DocUri.append("user-profile2/users/").append(Id).append("/user.xml");
DocUri.append("user-profile3/users/").append(Id).append("/user.xml");
}
return DocUri.toString();
}
Output Should Be :
where '1' is the Id passed to the above method
[user-profile1/users/1/user.xml, user-profile2/users/1/user.xml, user-profile3/users/1/user-profile.xml]
You can try out something like this,
public List<String> build(String Uri, String Id) {
List<String> values = new ArrayList<>();
if (Uri.contains("newString")) {
for (int i = 1; i <= 3; i++) {
values.add(String.format("user-profile%s/users/%s/user.xml",i,Id));
}
}
return values;
}
If you want to append more user-profile you can increase the value in for-loop

How do I access a specific element from a nested ArrayList

I have two ArrayLists
private ArrayList<ArrayList<String> dataList = new ArrayList<>();
//This is a class variable
ArrayList<String> dataRow = new ArrayList<>();
//This is a method variable
I add items to dataRow
dataRow.add("number");
dataRow.add("firstName");
dataRow.add("surname");
dataRow.add("dateStart");
dataRow.add("dateEnd");
and then I add each dataRow to dataList resulting in an ArrayList of ArrayLists
dataList.add(dataRow);
My Question is:
I need to select just elements 3 and 4 from each dataRow and I can't find any code that works.
I have tried
for (ArrayList<String> eachRow : dataList)
{
For (String eachElement : eachRow)
(
System.out.println(eachElement)
}
}
All this does is print out all the elements
I have also tried other code such as
dataList.get(eachElement)
this throws a no suitable method error in netbeans
I worked it out as soon as I had posted this.
The code in the inner for loop should be:
System.out.println(eachRow.get(4));
Assuming you want to extract only two array elements, you could use a simple POJO for that:
class YourPojo { // rename it to something self-explanatory
private String field3;
private String field4;
// getters & setters
}
Then define an utility method extracting the data into your POJO from the raw array:
static YourPojo extractYourPojo(List<String> rawData){
YourPojo pojo = new YourPojo();
pojo.setField3(rawData.get(3));
pojo.setField4(rawData.get(4));
return pojo;
}
Then you can use the method as follows:
List<YourPojo> extracted =
dataList.stream()
.map(ClassWithUtilityMethod::extractYourPojo)
.collect(toList());
You can have a class to store values like below,
class ExtractedValue {
private String value3;
private String value4;
public ExtractedValue(String value3, String value4) {
this.value3 = value3;
this.value4 = value4;
}
public String getValue3() {
return value3;
}
public String getValue4() {
return value4;
}
}
And use the below to extract the 3rd and 4th values,
List<ExtractedValue> extracted= dataList.stream().map(l -> new ExtractedValue(l.get(3), l.get(4)))
.collect(Collectors.toList());
To print you can use the below,
extracted.stream().forEach(e -> {
System.out.println(e.getValue3());
System.out.println(e.getValue4());
});

How to transform list of objects into one row object in java

I have a class A having private members like below.
class A {
String type;
}
The above class will come as list objects List . Now i have Another class B
Class B {
String type1;
String type2;
String type3;
String type4;
String type5;
String type6;
String type7;
String type8;
}
So Now How i have to iterate through List and get the (type(s)) data one by one and then put it into Class B as single object like first one will go to Type1 , second one ---> type2, third one--- > type3 ....., so on.
Note : There will be only 8 types in class A as a list . so we will have exactly 8 types in Class B and i have thought on reflection so please tell how do i use it, if this is the only option.
Jasper supports Map, so I would suggest you can store the values in a SortedMap, such as a TreeMap rather than a class with public variables.
Then you would add your type names like this:
Map<String, String> b = new TreeMap<>();
b.put("type1", "Foo");
b.put("type2", "Bar");
b.put("type3", "Baz");
...
Or if you're populating from a list of A:
List<A> list = ...;
Map<String, String> b = new TreeMap<>();
for (int i = 0; i < list.size(); i++) {
b.put("type" + (i + 1), list.get(i).type;
}
To iterate over all the names in the map, you could then use:
for (Map.Entry<String, String> entry: b.entrySet()) {
String key = entry.key();
String value = entry.value();
System.out.println(key + " = " + value);
}
If you can change the class B as:
class B
{
String[] types;
}
Then we can do:
int i = 0;
for(A aObject:aList){
bObject.types[i] = aObject.type;
}
Else we can add all types like this:
bObject.type1 = aList.get(0).type;
bObject.type2 = aList.get(1).type;
and so on.

Using a splitter on an Iterated LinkedList?

Just wondering if you can use a splitter class to split up details moved from a LinkedList to and iterated one? This is the code of the initial split I used before I iterated the LinkedList:
Scanner input = new Scanner(new File("today.txt"));
while (input.hasNextLine())
{
names = input.nextLine();
if(names.contains(":"))
{
splitter2 = names.split(":");
name = splitter2[0];
times = splitter2[1];
System.out.printf("%s\t\t %s \n",name, times);
}
q1.add(names);
}
Q1 being the LinkedList that i have created.
Is there anyway to split the iterated list so that i can only search for name when calling back the new Iterated List?
If I understand you correctly, a Map would suit your needs better than a LinkedList.
You can have a Map<String,String> where the key is name and the value is times. Or you can have a Map<String,SomeObject> where the key is the name and the value some object that contains the data you read from the line.
Then, instead of q1.add(names), you can have :
Map<String,String> map = new HashMap<>();
...
while (input.hasNextLine()) {
...
map.put (name,times);
...
}
or
Map<String,SomeObject> map = new HashMap<>();
...
while (input.hasNextLine()) {
...
map.put (name,new SomeObject(name,times);
...
}
Later you can search the map for a specific name (map.containsKey(name) or map.get(name)), or iterate over all the names (using map.keySet()).
This is a little unclear, but I think what you're looking for is a HashMap. If the idea is to put the names and times into a data structure so that you can later search by name, then you want a HashMap<String,String> map, and then
map.put(name,times);
to add to the map. Later on, you can retrieve the times for a particular name with
map.get(name);
There are some assumptions here:
You don't care about the order of the names (see LinkedHashMap if you do care).
The names are unique (see Guava's Multimap if they're not unique).
You can create a custom Class, change q1 to a list of this type, add the elements if they can be split.
final List<Person> q1=new LinkedList<Person>();
{...other code...}
//your code change to add to this list when split can occur
if(names.contains(":"))
{
splitter2 = names.split(":");
name = splitter2[0];
times = splitter2[1];
System.out.printf("%s\t\t %s \n",name, times);
q1.add(new Person(name,times);
}
Then you can iterate the list and compare the attribute name with a search key:
final String searchKey="george";
for(final Person person : q1){
if(person.getName().equalsIgnoreCase(searchKey))
System.out.println("I found " + searchKey +"!");
}
Person class:
public class Person {
private String name;
private String time;
public Person(String name, String time) {
this.name = name;
this.time = time;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setTime(String time) {
this.time = time;
}
public String getTime() {
return time;
}
}
Alternatively, you can iterate and split the String only list, during the iteration, in the same way you did before. The previous method is better.
Example:
public static void main(String[] args) {
final String search = "george";
List<String> q1 = new LinkedList<String>();
q1.add("tom:120000");
q1.add("george:130000");
q1.add("john:120000");
for (final String q : q1) { //for each string q in the list q1
if (q.contains(":")) {
final String[] split = q.split(":");
final String name = split[0];
final String time = split[1];
if (name.equalsIgnoreCase(search)) {
System.out.println("I found " + search + "!");
System.out.println(name + " : " + time);
break;
}
}
}
}

Use Collections to order ArrayList<HashMap<String,String>> comparing piece of string

I need sort ArrayList of HashMap, this is my code:
ArrayList<HashMap<String,String>> fiduList = new ArrayList<HashMap<String,String>>();
for (MapPoint aList: MapPointsList) {
HashMap<String, String> fidu = new HashMap<String, String>();
fidu.put(KEY_NAME, aList.getRealname());
fidu.put(KEY_TYPE, aList.getType());
fiduList.add(fidu);
}
getRealname get a string like this: AABB/CCCC/DDDD. For example:
AA11/4352/G435;
AA23/0234/J543;
AA02/0032/K123;
I need sort ArrayList comparing first DDDD, CCCC and then BB.
With my code I can sort only all string:
Collections.sort(fiduList, new Comparator<HashMap<String,String>>(){
public int compare(HashMap<String,String> mapping1,HashMap<String,String> mapping2){
return mapping1.get(KEY_NAME).compareTo(mapping2.get(KEY_NAME));
}
});
How can I solve the problem? (I'm new Java user).
Thank
I would suggest another approach. It seems that you use the map for holding two properties of an object - a name and a type. If so, a map is not the appropriate data structure.
You really should create an own class for it:
public final class Fidu {
private final String name;
private final String type;
public Fidu(String name, String type) {
this.name = name;
this.type = type;
}
}
When continuing to analyze the requirements, it seems as if the name consists of three parts, which must be parsed from a delimited string. Thus, your class should reflect that (note the private constructor and the factory method):
public final class Fidu {
private final String namePart1;
private final String namePart2;
private final String namePart3;
private final String type;
private Fidu(String namePart1, String namePart2, String namePart3, String type) {
this.namePart1 = namePart1;
this.namePart2 = namePart2;
this.namePart3 = namePart3;
this.type = type;
}
public static Fidu parse(String name, String type) {
String[] parts = name.split("/");
if (parts.length != 3)
throw new IllegalArgumentException(name);
return new Fidu(parts[0], parts[1], parts[2], type);
}
}
And finally, you should consider a natural ordering on the objects of type Fidu:
public final class Fidu implements Comparable<Fidu> {
...
public int compareTo(Fidu other) {
// an example:
int compare = this.namePart3.compareTo(other.namePart3);
if (compare != 0)
return compare;
compare = this.namePart2.compareTo(other.namePart2);
if (compare != 0)
return compare;
return this.namePart1.compareTo(other.namePart1);
}
}
Additionally this class obviously should also provide an implementation for hashCode and equals. Up to you ...
With that approach you do not need an ArrayList<HashMap<String, String>> anymore, but simply use a List<Fidu> (by the way, for the variable's types always use the interface and not an implementation). This list can then easily be sorted with
List<Fidu> fiduList = ...
Collections.sort(fiduList);
Change your sort from:
return mapping1.get(KEY_NAME).compareTo(mapping2.get(KEY_NAME));
To this:
String[] leftStrings = mapping1.get(KEY_NAME).split("/");
String[] rightStrings = mapping2.get(KEY_NAME).split("/");
int comp = 0;
for (int i = leftStrings.length - 1; i >=0; i--) {
comp = leftStrings[i].compareTo(rightStrings[i]);
if (comp != 0) {
break;
}
}
return comp;
This breaks your string into the three parts, then sorts the strings alphabetically working backwards. The first time we see a mismatch, we report the sort order.
In your Comparator#compare method you can use the class java.util.regex.Pattern to split up the real name using regular expressions:
Pattern pattern = Pattern.compile("(\\w{2})(\\w{2})/(\\w{4})/(\\w{4})");
Matcher matcher = pattern.matcher(realName);
if (matcher.matches()) {
String aa = matcher.group(1);
String bb = matcher.group(2);
String cccc = matcher.group(3);
String dddd = matcher.group(4);
// TODO: compare
} else {
// TODO: real name does not match pattern
}
Notes:
You need to compile the pattern only once (first line); it can then be reused. E.g put it into a static or non-static member variable.
\\w matches the following characters: 'a'-'z', 'A'-'Z', '0'-'9', '_'. If that's not sufficient, use other charachter classes or directly specify a custom character class like [A-Z0-9]
Extend TreeMap create your own map class, In this class provide your way to sort the Map objects, for your string comparisons you can pass the Comparator with your custom logic to TreeMap class.
http://docs.oracle.com/javase/7/docs/api/java/util/TreeMap.html
This way all the functionality of the Map will be available to you and you can also implement your own logic of sorting.

Categories

Resources