Using a splitter on an Iterated LinkedList? - java

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;
}
}
}
}

Related

Find the Oldest person from an array of persons which contains their name and yearOfBirth Java

I need to implement a method which should take an array of persons, basically public String oldest (Person [] persons), and return the oldest one. The persons which will be inputed are the following:
new Person("Augusta Ada King, grevinna av Lovelace", 1815),
new Person("Muhammad ibn Musa al-Khwarizmi", 780),
new Person("Alan Turing", 1912),
new Person("Grace Hopper", 1906)
Below you can find my class Called Person. I've tried all different solutions with basic for-loop but I feel really lost and would appreciate any input or recommendation how I should write the method to find the oldest person.
class Person {
String name;
int yearOfBirth;
public Person(String name, int yearOfBirth) {
this.name = name;
this.yearOfBirth = yearOfBirth;
}
public int getAge() {
return getAge(java.time.LocalDate.now().getYear());
}
public int getAge(int year) {
return year - yearOfBirth;
}
#Override
public String toString() {
return String.format("%s %d", name, yearOfBirth);
}
public String oldest(Person [] persons){
}
You can try this:
Person oldest = Arrays.stream(persons).max(Comparator.comparing(Person::getAge)).get();
You need to iterate over your persons array and check which yearOfBirth is greater. You can implement your method like below:
public String oldest(Person[] persons) {
Person oldestPerson = persons[0];
for (Person person : persons) {
if (person.getYearOfBirth() < oldestPerson.getYearOfBirth()) {
oldestPerson = person;
}
}
return oldestPerson.getName();
}
This method should be static since it has nothing to do with an instance, and otherwise you have to call the method from an instance, which you probably don't want to do
Want should happen if you have more then one (oldest) person with the same age?
Why should the return be only the name and not a Person?
public static String oldest(Person[] persons) {
if (persons == null){
throw new NullPointerException("persons == null");
}
if (persons.length == 0) {
return null; //or throw same Exception depending on your handling
}
Person oldestPerson = persons[0];
for (Person person : persons) {
if (person.yearOfBirth < oldestPerson.yearOfBirth) {
oldestPerson = person;
}
}
return oldestPerson.name;
}
Since there could be the possibility of more than one oldest person I would do it as follows:
Here is some data with two oldest people (sort of)
Person[] people = {
new Person("Augusta Ada King, grevinna av Lovelace",
1815),
new Person("Muhammad ibn Musa al-Khwarizmi", 780),
new Person("Another oldest person", 780),
new Person("Alan Turing", 1912),
new Person("Grace Hopper", 1906) };
String s = Person.oldest(people);
System.out.println(s);
prints
Muhammad ibn Musa al-Khwarizmi
Another oldest person
first I would make the method static since it doesn't rely on instance fields but an array of instances.
I would use a map to facilitate holding the the names of the people using their age as the key. Use the Map.merge method to populate the map and handle duplicate ages
Now iterate thru the names and as you do so:
find the oldest age.
store the name as the value for that age.
if another is found of the same age, concatenate the name with a newline(\n) and update the current map value.
when finished, return the value for the computed oldest individual(s).
public static String oldest(Person[] persons) {
int oldest = 0;
Map<Integer, String> ages = new HashMap<>();
for (Person p : persons) {
int age = p.getAge();
oldest = Math.max(oldest, age);
ages.merge(age, p.name, (last, current)- > last + "\n" + current);
}
return ages.get(oldest);
}
In case you would rather return a List of names your method can look like this. The main differences are:
return a List<String> which contains the names
using a Map<Integer, List<String>> to contain the people based on age.
computeIfAbsent to initialize the maps value for that age one time and then add the name to the list.
public static List<String> oldest(Person[] persons) {
int oldest = 0;
Map<Integer, List<String>> ages = new HashMap<>();
for (Person p : persons) {
int age = p.getAge();
oldest = Math.max(oldest, age);
ages.computeIfAbsent(age, v->new ArrayList<>()).add(p.name);
}
return ages.get(oldest);
}
It would then be called like so
List<String> list = Person.oldest(people);
list.foreach(System.out::println); // to print - same as before.
My final recommendation is that you use Lists over Arrays as they have advantages, the main on (imho) being that they grow dynamically as you add more items.

Remove the duplicates from a list and move the the other duplicate on top of the list

I'm trying to test a code that if I add new element to the list it detects the similar element and remove one of the duplicates but move the other one to the beginning of the list.
public class MemberList {
List<String> members;
public MemberList() {
this.members = new ArrayList<String>();
}
//This is the part I'm trying to fix!!!
public void addMember(String FirstName, String LastName) {
members.add(0, FirstName + " " + LastName);
}
}
Instead of ArrayList, I think you should use LinkedHashSet as no duplicated elements are allowed in your collection. And LinkedHashSet will reserve insertion order so when you detect a duplicate, you can remove old one and insert new one to set.
public class MemberList {
Set<String> members;
public MemberList() {
this.members = new LinkedHashSet<String>();
}
public void addMember(String FirstName, String LastName) {
String key = FirstName + " " + LastName;
if (members.contains(key)) {
members.remove(key);
}
members.add(key); // Always add to tail
}
}
Remember LinkedHashSet will always add new elements to the tail, so you need to get last element for your beginning case.
List way to accomplish the task (not preferred due to efficiency):
public void addMember(String FirstName, String LastName) {
String name = FirstName+" "+LastName;
if(members.contains(name)) { // checks if the list contains name value
members.remove(name); // removes the first occurrence of the name from the list
members.add(0,name); // adds the name to 0th position of the list
} else {
members.add(name); // if name not found in list, appends the value to the list
}
}

Using Collections and HashMap

I have the following class, its fairly simple, all i am doing is storing the variables from a URL.
class RM {
private String identifier, visible;
public String getIdentifier() {
return identifier;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
public String getVisible() {
return visible;
}
public void setVisible(String visible) {
this.visible = visible;
}
public RM (String identifier, //1
String visible; {
this.identifier = identifier; //1
this.visible = visible;
}
#Override
public String toString() {
return identifier + "\t" + visible + "\t";
}
}
This is stored in a collection List when i pass through the variables.
Collection<RM> attributes1 = new ArrayList<>();
I then obtain the variables stored in the identifier field and store them in an array like below:
Object rowDataprelim1 [] = new Object[1];
RM rm = null;
Iterator<RM> iterator = attributes1.iterator();
while(iterator.hasNext()) {
rm = iterator.next();
rowDataprelim1[0] = rm.identifier;
System.out.println(rm.identifier);
I then create a HashMap, the reason for doing so is because i want unique entries only.
Map<Object, Integer> numberMapping = new HashMap<>();//create a new hashmap
And also create an array of which i store identifier into rowData[0].
Object rowData[] = new Object[2];
Iterator it = numberMapping.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry) it.next();
rowData[0] = attributes1.get((int) pair.getValue()).identifier;
it.remove();
}
What i cant get right is the syntax to get the value of identifier from my collections list, i believe the syntax i have used is for an Arraylist.
rowData[0] = attributes1.get((int)pair.getValue()).identifier;
Can someone advise the correct syntax, i only want to get identifier and not the visible. I in fact have around 30 items in my class and only want to get 12 of them for the first section of my project. I have never used collection before and i have been told to use Collection and not ArrayList.
Any help is much appreciated.

Process multiple csv lines with 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

Create a Map from a CSV type data [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I have the following data stored in a ".txt" file:
Dave,40,04/05/1978
Scott,34,05/06/1986
Sam,24,04/05/1978
Love,32,04/06/1989
Harry,29,04/06/1989
I have used the BufferedReader to read, split (using ,) and store it in a String[] stringArray.
Now stringArray[0] will have name, stringArray[1] will have number and stringArray[2] will have date.
I am now looking to build a HashMap like below to display the key as date (in String) and value as List of Members having the same date of birth
Expected output:
DOBMap: {04-05-1978=[[Dave,40],[Same,24]], 05/06/1986=[[Scott,34]], 04/06/1989=[[Love,32],[Harry,29]]
I have Member which has the following variables:
private String name;
private String no;
private String DOB;
Since I am a novice for collections, I am seeking help to achieve this DOBMap output.
I think you can do better by using Java Stream API (https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html).
Here I assume that your Memeber class has the constructor:
Member(String[] array)
In which case the following:
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import static java.util.stream.Collectors.groupingBy;
public class SO1 {
public static void main(String[] args) {
String filePath = ".../src/main/resources/SO1.txt";
try (Stream<String> lines = Files.lines(Paths.get(filePath))) {
Map<String, List<Member>> map = lines
.map(line -> line.split(","))
.map(Member::new)
.collect(groupingBy(Member::getDOB));
System.out.println(map);
} catch (Exception e) {
e.printStackTrace();
}
}
}
prints:
{05/06/1986=[Member{name='Scott', no='34', dob='05/06/1986'}], 04/05/1978=[Member{name='Dave', no='40', dob='04/05/1978'}, Member{name='Sam', no='24', dob='04/05/1978'}], 04/06/1989=[Member{name='Love', no='32', dob='04/06/1989'}, Member{name='Harry', no='29', dob='04/06/1989'}]}
Arguably, the intent of this code is more clear then a code that iterates explicitly.
You could just iterate through all of the members and insert them in a HashMap. I used ArrayList in this example, but if you would like, I can rewrite it with a regular array.
So lets say you have an ArrayList called members.
// members is an ArrayList of Member objects
HashMap<String, ArrayList<ArrayList<String>>> dobMap = new HashMap<>();
for (Member m : members) {
String[] temp = {m.getName(), m.getNo()}; // e.g. [Dave, 40]
// already in the map, so just push it to the existing ArrayList in there
if (dobMap.containsKey(m.getDOB())) {
dobMap.get(m.getDOB()).add(temp); // e.g. [[Dave, 40]].add([Sam, 24])
} else { // not in the map yet, so push a new ArrayList to that spot
ArrayList<String[]> temp2 = new ArrayList<>();
temp2.add(temp); // e.g. [[Dave, 40]]
dobMap.put(m.getDOB(), temp2);
}
}
A slightly different solution (using an ArrayList of ArrayList instead of an ArrayList of String[]):
HashMap<String, ArrayList<ArrayList<String>>> dobMap = new HashMap<>();
for (Member m : members) {
ArrayList<String> temp = new ArrayList<>();
temp.add(m.getName());
temp.add(m.getNo());
if (dobMap.containsKey(m.getDOB())) {
dobMap.get(m.getDOB()).add(temp);
} else {
ArrayList<ArrayList<String>> temp2 = new ArrayList<>();
temp2.add(temp);
dobMap.put(m.getDOB(), temp2);
}
}
With that, you can simply run System.out.println(dobMap); and see that the result is exactly as you expect. Printing the HashMap from the first solution will require some effort to print out the contents of the HashMap since it won't print the regular array nicely like it does for ArrayList. But they both store the information in the same way.
But I think instead of storing an ArrayList of ArrayList, you should just be storing it as an ArrayList of Member. So I will show a third solution, which is this:
HashMap<String, ArrayList<Member>> dobMap = new HashMap<>();
for (Member m : members) {
if (dobMap.containsKey(m.getDOB())) {
dobMap.get(m.getDOB()).add(m);
} else {
ArrayList<Member> temp = new ArrayList<>();
temp.add(m);
dobMap.put(m.getDOB(), temp);
}
}
And then override toString() in Member like so:
#Override
public String toString() {
return String.format("[%s, %s]", this.name, this.no);
}
This third solution seems to be the most clear.
In this example, I used the following Member class as a basis:
class Member {
private String name, no, dob;
public Member(String name, String no, String dob) {
this.name = name;
this.no = no;
this.dob = dob;
}
public String getName() { return this.name; }
public String getNo() { return this.no; }
public String getDOB() { return this.dob; }
}
An example of how you might define your ArrayList of Member object would be:
// parts is an array of length 3 like you said
ArrayList<Member> members = new ArrayList<>();
members.add(new Member(parts[0], parts[1], parts[2]);

Categories

Resources