I have a text file with values like :
[2014-08-19 00:00:21,702] REC|SRC:923142676343|DST:9900|CNT:1|OPR:zong|\nADD BBCLANDAN\n
[2014-08-19 00:01:02,958] REC|SRC:923138824807|DST:9900|CNT:1|OPR:zong|ADD TRIXXS
[2014-08-19 00:01:12,799] REC|SRC:923125473547|DST:9900|CNT:1|OPR:zong|ADD SahafatMedia
[2014-08-19 00:01:32,894] REC|SRC:923142676343|DST:9900|CNT:1|OPR:zong|ADD BBCMEDIA\n\n
[2014-08-19 00:02:42,754] REC|SRC:923119511824|DST:9900|CNT:1|OPR:zong|ADD sMs
[2014-08-19 00:01:43,753] REC|SRC:923119511824|DST:9900|CNT:1|OPR:zong|ADD RIDAsMs
i have raed the text file and stored it into an arraylist with the output:
output:
923119511824|DST:9900|CNT:1|OPR:zong|ADD RIDAsMs
923119511824|DST:9900|CNT:1|OPR:zong|ADD sMs
923125473547|DST:9900|CNT:1|OPR:zong|ADD SahafatMedia
923138824807|DST:9900|CNT:1|OPR:zong|ADD TRIXXS
923142676343|DST:9900|CNT:1|OPR:zong|ADD BBCMEDIA\n\n
923142676343|DST:9900|CNT:1|OPR:zong|\nADD BBCLANDAN\n
[2014-08-19 00:01:02,958] REC|
[2014-08-19 00:01:12,799] REC|
[2014-08-19 00:01:32,894] REC|
[2014-08-19 00:01:43,753] REC|
[2014-08-19 00:02:42,754] REC|
[2014-08-19 00:00:21,702] REC|
Now i want to tokenize this arraylist to display only the duplicate contact numbers which are in output e.g 923142676343 and their content which are after ADD e.g TRIXXS
I need help please ???
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
public class pring
{
public static final String FILE_LOCATION = "C:/Users/DfroJaCk DB/Desktop/zongrecv.txt";
public static void main ( String [ ] args )
{
//Your reader
BufferedReader in = null;
//Where you store the Strings
ArrayList < String > al = new ArrayList < String > ();
try
{
//Open the file and give it to the reader
in = new BufferedReader ( new FileReader ( FILE_LOCATION ) );
String line;
//As long as the file has more lines read a line at a time
while ( ( line = in.readLine () ) != null )
{
//Split the line and stoe it in an array
String [ ] splitLine = line.split ( "SRC:" );
for ( int i = 0; i < splitLine.length; i++ )
{
//Add each element of the split array into an ArrayList
al.add ( splitLine [ i ] );
}
}
//Catch your possible problems
} catch ( FileNotFoundException fnfe )
{
fnfe.printStackTrace ();
} catch ( IOException ioe )
{
ioe.printStackTrace ();
}
//Sort your list
Collections.sort ( al );
for ( String s : al )
{
//spit it out
System.out.println ( s );
}
}
}
You could use java StringTokenizer. Since your arraylist is already sorted, you only have to check consecutive positions. Use | as a delimiter, get the first token for each entry that contains a number and compare it to the first token of the following entry. If they are equal, get the index of the space in the last token and print what is after it.
Be carefull to consider the case when more that 2 entries contain the same phone number, don't print them twice.
But you might rethink your approach, the way you store the Strings in the ArrayList looks pretty messy.
List<String> myList = new ArrayList();
myList.add("923119511824|DST:9900|CNT:1|OPR:zong|ADD RIDAsMs");
myList.add("923119511824|DST:9900|CNT:1|OPR:zong|ADD sMs");
myList.add("923125473547|DST:9900|CNT:1|OPR:zong|ADD SahafatMedia");
Collections.sort(myList);
System.out.println(myList.toString());
for (int i = 0; i < myList.size() - 1; i++) {
String currentEntry = myList.get(i);
String nextEntry = myList.get(i + 1);
StringTokenizer tokenizer = new StringTokenizer(currentEntry, "|");
String currentNumber = tokenizer.nextToken();
tokenizer = new StringTokenizer(nextEntry, "|");
String nextNumber = tokenizer.nextToken();
String lastToken = "";
if (currentNumber.equals(nextNumber)) {
System.out.println(currentNumber + " duplicate");
while (tokenizer.hasMoreTokens()) {
lastToken = tokenizer.nextToken();
}
System.out.println("last token: " + lastToken);
int index = lastToken.indexOf(" ");
System.out.println("What you probably want: " + lastToken.substring(index + 1));
}
}
And the output for this would be:
[923119511824|DST:9900|CNT:1|OPR:zong|ADD RIDAsMs, 923119511824|DST:9900|CNT:1|OPR:zong|ADD sMs, 923125473547|DST:9900|CNT:1|OPR:zong|ADD SahafatMedia]
923119511824 duplicate
last token: ADD sMs
What you probably want: sMs
Related
I have this text that I want to read the first column from in my project named Data.txt.
//column names: productId, name,numInStock,provider,pricePerUnit
private static String records = "231A,Light Bulb,123,Wilco,1.75:"+
"113D,Hairbrush,19,Aamco,3.75:"+
"521W,Shampoo,24,Acme,6.95:"+
"440Q,Dishwashing Detergent,20,Wilco,1.75:"+
"009G,Toothbrush,77,Wilco,0.85:"+
"336C,Comb,34,Wilco,0.99:"+
"523E,Paper Pad Set,109,Congdon and Chrome,2.45:"+
"888A,Fake Diamond Ring,111,Americus Diamond,3.95:"+
"176A,Romance Nove1 1,20,Barnes and Noble,3.50:"+
"176B,Romance Nove1 2,20,Barnes and Noble,3.50:"+
"176C,Romance Nove1 3,20,Barnes and Noble,3.50:"+
"500D,Floss,44,Wilco,1.25:"+
"135B,Ant Farm,5,Wilco,8.00:"+
"211Q,Bicycle,9,Schwinn,75.95:"+
"932V,Pen Set,50,Congdon and Chrome,9.95:"+
"678Q,Pencil 50,123,Congdon and Chrome,9.95:"+
"239A,Colored Pencils,25,Congdon and Chrome,4.75:"+
"975B,Shower Curtain,25,Wilco,6.50:"+
"870K,Dog Bowl,15,Wilco,4.75:"+
"231S,Cat Bowl,15,Wilco,4.75:"+
"562M,Kitty Litter,15,Wilco,3.25:"+
"777X,Dog Bone,15,Wilco,4.15:"+
"933W,Cat Toy,15,Wilco,2.35:"+
"215A,Hair Ball,0,Little Jimmy,0.00:";
I wrote this code to do so but I am not getting the desired output.
My code is
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
Scanner input = new Scanner(System.in);
File file = new File("C:\\Users\\student\\Desktop\\workspace\\Welcome\\src\\Data.txt");
input = new Scanner(file);
while (input.hasNextLine()) {
String line = input.nextLine();
String[] words = line.split(",");
System.out.println(words[0]);
input.useDelimiter(",");
}
input.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
I want to get the output in this format
134A
213A
911C
012E
662Z
This is the output I got I want to remove the part that says private static String records = and also the ".
//column names: productId
private static String records = "231A
"113D
"521W
"440Q
"009G
"336C
"231S
You're sort-of on the right track with the delimeters.
Here's how I did it and it can be cleaned up a bit, and you'll have to make a for loop to iterate through the arraylist and get each one, and split each one and print each one's 0'th index ( "str" is the string/text file you provided )
Scanner in = new Scanner(str) ;
in.useDelimiter(":") ;
ArrayList<String> al = new ArrayList<>() ;
while( in.hasNext())
{
al.add(in.next() ) ;
}
for( int i = 0 ; i < al.size(); ++i )
{
String s = al.get(i) ;
String[] s2 = s.split(",") ;
System.out.println( s2[0] );
}
import java.io.*;
import java.util.*;
class A {
public static void main(String args[]) throws Exception {
Console con = System.console();
String str;
int i=0;
HashMap map = new HashMap();
HashSet set = new HashSet();
System.out.println("Enter File Name : ");
str = con.readLine();
File f = new File(str);
f.createNewFile();
FileInputStream fis = new FileInputStream(str);
StreamTokenizer st = new StreamTokenizer(fis);
while(st.nextToken()!=StreamTokenizer.TT_EOF) {
String s;
switch(st.ttype) {
case StreamTokenizer.TT_NUMBER: s = st.nval+"";
break;
case StreamTokenizer.TT_WORD: s = st.sval;
break;
default: s = ""+((char)st.ttype);
}
map.put(i+"",s);
set.add(s);
i++;
}
Iterator iter = set.iterator();
System.out.println("Frequency Of Words :");
while(iter.hasNext()) {
String word;
int count=0;
word=(String)iter.next();
for(int j=0; j<i ; j++) {
String word2;
word2=(String)map.get(j+"");
if(word.equals(word2))
count++;
}
System.out.println(" WORD : "+ word+" = "+count);
}
System.out.println("Total Words In Files: "+i);
}
}
In This code First I have already created a text file which contains the following data :
# Hello Hii World # * c++ java salesforce
And the output of this code is :
**Frequency Of Words :
WORD : # = 1
WORD : # = 1
WORD : c = 1
WORD : salesforce = 1
WORD : * = 1
WORD : Hii = 1
WORD : + = 2
WORD : java = 1
WORD : World = 1
WORD : Hello = 1
Total Words In Files: 11**
where i am unable to find why this shows c++ as a seperate words . I
want to combine c++ as a single word as in the output
You can do it in this way
// Create the file at path specified in the String str
// ...
HashMap<String, Integer> map = new HashMap<>();
InputStream fis = new FileInputStream(str);
Reader bufferedReader = new BufferedReader(new InputStreamReader(fis));
StreamTokenizer st = new StreamTokenizer(bufferedReader);
st.wordChars('+', '+');
while(st.nextToken() != StreamTokenizer.TT_EOF) {
String s;
switch(st.ttype) {
case StreamTokenizer.TT_NUMBER:
s = String.valueOf(st.nval);
break;
case StreamTokenizer.TT_WORD:
s = st.sval;
break;
default:
s = String.valueOf((char)st.ttype);
}
Integer val = map.get(s);
if(val == null)
val = 1;
else
val++;
map.put(s, val);
}
Set<String> keySet = map.keySet();
Iterator<String> iter = keySet.iterator();
System.out.println("Frequency Of Words :");
int sum = 0;
while(iter.hasNext()) {
String word = iter.next();
int count = map.get(word);
sum += count;
System.out.println(" WORD : " + word + " = " + count);
}
System.out.println("Total Words In Files: " + sum);
Note that I've updated your code using Generics instead of the raw version of HashMap and Iterator. Moreover, the constructor you used for StreamTokenizer was deprecated. The use of both map and set was useless because you can iterate over the key set of the map using .keySet() method. The map now goes from String (the word) to Integer (the number of word count).
Anyway, regarding the example you did, I think that a simple split method would have been more appropriate.
For further information about the wordChars method of StreamTokenizer you can give a look at #wordChars(int, int)
I have a csv file which is hashmapped, whenever the user enter the city name(key) it will display all the details of that city. I have to optimize the search result time, everytime the it is reading the file(instead of only once) and displaying the values.
The CSV files contains data like this :
city,city_ascii,lat,lng,country,iso2,iso3,admin_name,capital,population,id
Malishevë,Malisheve,42.4822,20.7458,Kosovo,XK,XKS,Malishevë,admin,,1901597212
Prizren,Prizren,42.2139,20.7397,Kosovo,XK,XKS,Prizren,admin,,1901360309
Zubin Potok,Zubin Potok,42.9144,20.6897,Kosovo,XK,XKS,Zubin
Potok,admin,,1901608808
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;
import java.io.IOException;
public class CSVFileReaders{
public static void main(String[] args) {
String filePath = "C:\\worldcities1.csv";
Scanner in = new Scanner(System.in);
System.out.println(" \n Enter the City name to be Searched : \n _> ");
long start = System.currentTimeMillis();
String searchTerm = in.nextLine();
readAndFindRecordFromCSV(filePath, searchTerm);
long end = System.currentTimeMillis();
System.out.println(" \n It took " + (end - start) + " Milli Seconds to search the result \n");
in.close();
}
public static void readAndFindRecordFromCSV( String filePath, String searchTerm) {
try{
HashMap<String,ArrayList<String>> cityMap = new HashMap<String,ArrayList<String>>();
Scanner x = new Scanner (new File(filePath),"UTF-8");
String city= "";
while(x.hasNextLine()) {
ArrayList<String> values = new ArrayList<String>();
String name = x.nextLine();
//break each line of the csv file to its elements
String[] line = name.split(",");
city = line[1];
for(int i=0;i<line.length;i++){
values.add(line[i]);
}
cityMap.put(city,values);
}
x.close();
//Search the city
if(cityMap.containsKey(searchTerm)) {
System.out.println("City name is : "+searchTerm+"\nCity details are accordingly in the order :"
+ "\n[city , city_ascii , lat , lng , country , iso2 , iso3 , admin_name , capital , population , id] \n"
+cityMap.get(searchTerm)+"");
}
else {
System.out.println("Enter the correct City name");
}
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}`
the time should be optimized and every time i search it is reading the entire file(which should happen)
Currently you mix the map initialization inside the search function.
You don't want that.
First, init the map, then use it in the search function.
To do that, extract a method for statements that instantiate and value the map and then refactor the readAndFindRecordFromCSV() method so that it accepts a Map as additional parameter :
public static void readAndFindRecordFromCSV( String filePath, String searchTerm, HashMap<String,ArrayList<String>> dataByCity) {...}
With refactoring IDE features, it should be simple enough : "extracting method" then "change signature".
Here is a code (not tested at runtime but tested at compile time) that splits the logical in separated tasks and also rely on instance methods :
public class CSVFileReaders {
private final String csvFile;
private HashMap<String, ArrayList<String>> cityMap;
private final Scanner in = new Scanner(System.in);
public static void main(String[] args) {
String filePath = "C:\\worldcities1.csv";
CSVFileReaders csvFileReaders = new CSVFileReaders(filePath);
csvFileReaders.createCitiesMap();
csvFileReaders.processUserFindRequest(); // First search
csvFileReaders.processUserFindRequest(); // Second search
}
public CSVFileReaders(String csvFile) {
this.csvFile = csvFile;
}
public void createCitiesMap() {
cityMap = new HashMap<>();
try (Scanner x = new Scanner(new File(csvFile), "UTF-8")) {
String city = "";
while (x.hasNextLine()) {
ArrayList<String> values = new ArrayList<String>();
String name = x.nextLine();
//break each line of the csv file to its elements
String[] line = name.split(",");
city = line[1];
for (int i = 0; i < line.length; i++) {
values.add(line[i]);
}
cityMap.put(city, values);
}
x.close();
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
public void processUserFindRequest() {
System.out.println(" \n Enter the City name to be Searched : \n _> ");
long start = System.currentTimeMillis();
String searchTerm = in.nextLine();
long end = System.currentTimeMillis();
System.out.println(" \n It took " + (end - start) + " Milli Seconds to search the result \n");
//Search the city
if (cityMap.containsKey(searchTerm)) {
System.out.println("City name is : " + searchTerm + "\nCity details are accordingly in the order :"
+ "\n[city , city_ascii , lat , lng , country , iso2 , iso3 , admin_name , capital , population , id] \n"
+ cityMap.get(searchTerm) + "");
} else {
System.out.println("Enter the correct City name");
}
}
}
The interesting part is here :
String filePath = "C:\\worldcities1.csv";
CSVFileReaders csvFileReaders = new CSVFileReaders(filePath);
csvFileReaders.createCitiesMap();
csvFileReaders.processUserFindRequest(); // First search
csvFileReaders.processUserFindRequest(); // Second search
The logical is clearer now.
Why do you create / load the CSV into a HashMap with every search ?
Just create the HashMap only once in the beginning, and then on every search just check whether it exists in the HashMap, eg move the read part into a separate method :
HashMap<String,ArrayList<String>> cityMap = new HashMap<String,ArrayList<String>>();
public static void readCSVIntoHashMap( String filePath) {
try{
Scanner x = new Scanner (new File(filePath),"UTF-8");
String city= "";
while(x.hasNextLine()) {
ArrayList<String> values = new ArrayList<String>();
String name = x.nextLine();
//break each line of the csv file to its elements
String[] line = name.split(",");
city = line[1];
for(int i=0;i<line.length;i++){
values.add(line[i]);
}
cityMap.put(city,values);
}
x.close();
...
}
Then have a separate method for searching :
public static void search(String searchTerm) {
if(cityMap.containsKey(searchTerm)) {
...
}
}
So I constructed some simple code to compare two text files. One with a jumbled list of words that are supposed to match up to words in the dictionary file. Basically finding which jumbled words match to their dictionary word. Some words have a few jumbled words that match to them, some don't have any matches. I'm looking to change this code to be much simpler, using HashMaps to make the program simpler and faster, but I'm not very good with HashMaps at all and could use the help.
Here is the code I currently have for the non-hashmap version if it helps:
import java.util.*;
import java.io.*;
public class Project6
{
public static void main(String[] args) throws Exception
{
if (args.length < 2 ) die( "Must give name of two input files on cmd line." );
BufferedReader dFile = new BufferedReader( new FileReader( args[0] ) );
BufferedReader jFile = new BufferedReader( new FileReader( args[1] ) );
ArrayList<String> jWordList= new ArrayList<String>();
ArrayList<String> dWordList= new ArrayList<String>();
long startTime = System.currentTimeMillis();
while (dFile.ready())
{
String word = dFile.readLine();
dWordList.add( word );
}
dFile.close();
while (jFile.ready())
{
String word = jFile.readLine();
jWordList.add( word );
}
jFile.close();
Collections.sort( dWordList );
Collections.sort( jWordList );
String[] dArray = dWordList.toArray(new String[dWordList.size()]);
String[] jArray = jWordList.toArray(new String[jWordList.size()]);
dArray = canonArray( dArray );
jArray = canonArray( jArray );
for(int i = 0 ; i < jWordList.size() ; i++)
{
String jWord = jArray[i];
System.out.print(jWordList.get(i) + " ");
for(int c = 0 ; c < dWordList.size() ; c++)
{
String dWord = dArray[c];
if(jWord.equals(dWord))
{
System.out.print(dWordList.get(c) + " ");
}
}
System.out.println();
}
long endTime = System.currentTimeMillis();
long ms = endTime-startTime;
System.out.println("Elapsed time in seconds: " + ms/1000.0 + "\n"); // 1 ms is a 1,000th of a second
}
private static void die( String errmsg )
{
System.out.println( "\nFATAL ERROR: " + errmsg + "\n" );
System.exit(0);
}
private static String toCanonical( String word )
{
char[] charArray = word.toCharArray();
Arrays.sort(charArray);
String charNewString = new String(charArray);
return charNewString;
}
private static String[] canonArray( String[] Arr )
{
String[] newArr = new String[Arr.length];
for(int i = 0 ; i < Arr.length ; i++)
{
String temp = toCanonical(Arr[i]);
newArr[i] = temp;
}
return newArr;
}
}
It produces the following output, which I would like to keep exactly the same (minus the print of elapsed time):
What you want is to define a HashMap such that the key's hash and equals method will come out the same regardless of the order and case of the string's characters. The following takes a String and converts it to lowercase and sorts the characters.
import java.util.*;
import java.io.*;
public class Project6 {
public static void main(String[] args) throws Exception {
if (args.length < 2) die("Must give name of two input files on cmd line.");
BufferedReader dFile = new BufferedReader(new FileReader(args[0]));
BufferedReader jFile = new BufferedReader(new FileReader(args[1]));
HashMap<String, List<String>> dWordMap = new HashMap<String, List<String>>();
long startTime = System.currentTimeMillis();
while (dFile.ready()) {
String word = dFile.readLine();
if (word == null) break;
addWord(word, dWordMap);
}
dFile.close();
while (jFile.ready()) {
String jWord = jFile.readLine();
if (jWord == null) break;
List<String> dWords = dWordMap.get(createKey(jWord));
if (dWords != null) {
System.out.println(jWord + " " + dWords);
}
}
jFile.close();
long endTime = System.currentTimeMillis();
long ms = endTime - startTime;
System.out.println("Elapsed time in seconds: " + ms / 1000.0 + "\n");
}
private static void die(String errmsg) {
System.out.println("\nFATAL ERROR: " + errmsg + "\n");
System.exit(0);
}
private static String createKey(String word) {
char[] chword = word.toLowerCase().toCharArray();
Arrays.sort(chword);
return new String(chword);
}
private static void addWord(String word, Map<String, List<String>> map) {
String key = createKey(word);
List<String> list = map.get(key);
if(list==null) {
list = new ArrayList<String>();
map.put(key, list);
}
list.add(word);
}
}
How can I count the number of cities per country from the data file? I would also like to display the value as percentage of the total.
import java.util.StringTokenizer;
import java.io.*;
public class city
{
public static void main(String[] args)
{
String[] city = new String[120];
String country = null;
String[] latDegree =new String[120];
String lonDegree =null;
String latMinute =null;
String lonMinute =null;
String latDir = null;
String lonDir = null;
String time = null;
String amORpm = null;
try
{
File myFile = new File("CityLongandLat.txt");
FileReader fr = new FileReader(myFile);
BufferedReader br = new BufferedReader(fr);
String line = null;
int position =0;
int latitude=0;
while( (line = br.readLine()) != null)
{
// System.out.println(line);
StringTokenizer st = new StringTokenizer(line,",");
while(st.hasMoreTokens())
{
city[position] = st.nextToken();
country = st.nextToken();
latDegree[latitude] =st.nextToken();
latMinute =st.nextToken();
latDir = st.nextToken();
lonDegree =st.nextToken();
lonMinute =st.nextToken();
lonDir = st.nextToken();
time = st.nextToken();
amORpm = st.nextToken();
}
if(city.length<8)
{
System.out.print(city[position] + "\t\t");
}
else
{
System.out.print(city[position] + "\t");
}
if(country.length()<16)
{
System.out.print(country +"\t\t");
}
else
{
System.out.print(country);
}
System.out.print(latDegree + "\t");
System.out.print(latMinute + "\t");
System.out.print(latDir + "\t");
System.out.print(lonDegree + "\t");
System.out.print(lonMinute + "\t");
System.out.print(lonDir + "\t");
System.out.print(time + "\t");
System.out.println(amORpm + "\t");
position++;
}
br.close();
}
catch(Exception ex)
{
System.out.println("Error !!!");
}
}
}
One easy way that comes to my mind would be as follows...
Create a hashMap Object where the key is a string (the country) and the value is an integer (number of cities found for the country) so it would be something like
Map countryResultsFoundMap = new HashMap< String,Integer>();
In short, for each row you would pick the country, (I would recommend that you .trim() and .toLowerCase() the value first) and check if it is existing in the hashMap, if not, add the entry like countryResultsFoundMap.put(country,0), otherwise, if the country already exists the pick the value from the hashMAp and add +1 to its integer value.
Eventually you will have all the values stored in the map and you can have access to that data for your calculations.
Hope that helps
"here are some of the output from the data file from my programme"
Aberdeen Scotland 57 2 [Ljava.lang.String;#33906773 9 N [Ljava.lang.String;#4d77c977 9 W 05:00 p.m. Adelaide Australia 34 138 [Ljava.lang.String;#33906773 55 S [Ljava.lang.String;#4d77c977 36 E 02:30 a.m...
The reason why your getting that output, is because you're trying to print the array object latDegree.
String[] latDegree
...
System.out.print(latDegree + "\t");
Also, you have lattitude = 0; but you never increment it, so it will always use the index 0 for the array. You need to increment it, like you did position++.
So for the print statement, print the print the value at index lattitude, not the entire array
Try this
System.out.print(latDegree[lattitude] + "\t");
...
lattitude++;
If for some reason you do want to print the array, then use Arrays.toString(array); or just iterate through it
I would also start with a map, and group the cities by country with a map.
Map<String,<List<String>>
Where the key is the country and the value is the list of cities in this country. With the size() methods you can perform the operations cities per country and percentage of total.
When you read one line you check if the key (country) already exists, if not you create a new list and add the city, otherwise add the city only to the existing list.
As a starter you could use the following snippet. However this sample assumes that the content of the file is read already and given as an argument to the method.
Map<String,List<String>> groupByCountry(List<String> lines){
Map<String,List<String>> group = new HashMap<>();
for (String line : lines) {
String[] tokens = line.split(",");
String city = tokens[0];
String country = tokens[1];
...
if(group.containsKey(country)){
group.get(country).add(city);
}else{
List<String> cities = new ArrayList<>();
cities.add(city);
group.put(country, cities);
}
}
return group;
}