I have a TreeMap with 3 entries, all from individual ArrayLists.
I use the following code:
Map<String, List<String>> mapOne = new TreeMap<String, List<String>>();
List<String> listFour = Arrays.asList("");
ArrayList<String> listOne = new ArrayList<>();
listOne.add("Writer");
listOne.add("Actor");
listOne.add("Politician");
listOne.add("Dancer");
ArrayList<String> listTwo = new ArrayList<>();
listTwo.add("James");
listTwo.add("Robert");
listTwo.add("Tereza");
listTwo.add("John");
ArrayList<String> listThree = new ArrayList<>();
listThree.add("Joyce");
listThree.add("Redford");
listThree.add("May");
listThree.add("Travolta");
for (int i = 0; i < listOne.size(); i++) {
String stringOne = listOne.get(i);
String stringTwo = listTwo.get(i);
String stringThree = listThree.get(i);
listFour = Arrays.asList(stringTwo, stringThree);
mapOne.put(stringOne, listFour);
}
Now I want to obtain the individual String values from the sorted list. like so:
for (Map.Entry<String, List<String>> entry : mapOne.entrySet()) {
String key = entry.getKey();
for (String value : entry.getValue()) {
System.out.println(value);
}
}
The above code prints a list like
{Robert Redford , John Travolta , Tereza May , James Joyce}
Is it possible to iterate over the list in a way as to obtain to separate lists, one with the first names and the other with the last names?
listOne = {Robert , John , Tereza, James}
listTwo = {Redford, Travolta, May, Joyce}
Or should I use an entirely different approach?
The whole thing started out with the need to sort one ArrayList and to other accordingly. What seemed trivial at the beginning, turned out to be a real challenge.
I am a sort of a hobby programmer, so the pros out there kindly bear with me.
It seems you're over-engineering somehow.
I will answer with a Stream solution first, just for the sake of trying it.
Note that I'd, personally, prefer the "old" iterative approach (see below).
// You can see by the use of AtomicInteger that this isn't the right road to take!
final AtomicInteger i = new AtomicInteger();
final Collection<List<String>> values1 =
mapOne.values()
.stream()
.flatMap(v -> v.stream())
.collect(partitioningBy(o -> i.getAndIncrement() % 2 != 0))
.values();
Output: [[Robert, John, Tereza, James], [Redford, Travolta, May, Joyce]]
Iterative approach
final Collection<String> names = new ArrayList<>();
final Collection<String> surnames = new ArrayList<>();
for (final List<String> value : mapOne.values()) {
names.add(value.get(0));
surnames.add(value.get(1));
}
Output:
[Robert, John, Tereza, James]
[Redford, Travolta, May, Joyce]
This is safe because you know each inner List has two elements.
What JB Nizet is telling you to do (credit to him for writing that), is basically to create an appropriate class
public class Person {
private String profession;
private String name;
private String surname;
// Getters and setters. JavaBean style
}
And proceed to sort a Collection<Person>.
For example, keeping it as simple as possible
final List<Person> persons = new ArrayList<>();
// Populate list
Collections.sort(persons, (p1, p2) -> {
// Not null-safe
return p1.getName().compareTo(p2.getName());
});
This will sort the list by name. It will not return a new List, but simply modify the input one.
Putting all the valuable tips, online searches and my efforts together, this is my final solution (in the hope that it might be useful to others). It seems to me my solution is minimal and straightforward :
List<Sites> listOfSites = new ArrayList<Sites>();
for (int i = 0; i < classLists.listSites.size(); i++) {
String site = classLists.listSites.get(i);
String description = classLists.listSitesDesc.get(i);
String link = classLists.listSitesLinks.get(i);
listOfSites.add(new Sites(site, description, link));
}
Collections.sort(listOfSites, (p1, p2) -> {
return p1.getName().compareTo(p2.getName());
});
final ArrayList<String> titles = new ArrayList<>();
final ArrayList<String> descriptions = new ArrayList<>();
final ArrayList<String> links = new ArrayList<>();
for (Sites s : listOfSites) {
String name = s.getName();
String description = s.getDesc();
String link = s.getLink();
titles.add(name);
descriptions.add(description);
links.add(link);
}
Below the class Sites:
public class Sites implements Comparable<Sites> {
private String name;
private String description;
private String link;
public Sites(String name, String description, String link) {
this.name = name;
this.description = description;
this.link = link;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return description;
}
public void setDesc(String description) {
this.description = description;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
}
Related
I have a little problem that is driving me crazy.
I have a
List<Integer> with ids.
List<ObjectA> with 3 variables:
an id, and two string
I have to sort the second list by putting at the top the elements with id contained in the first list, then by string asc and by the second string asc.
What is the easiest way to make this work? I am trying to use the .sort(), Comparators etc.
An example:
#Getter
#Setter
public class ObjectA {
private Integer id;
private String code;
private String name;
}
// comparator:
static class SortByCode implements Comparator<ObjectA> {
public int compare(ObjectA a, ObjectA b) {
String as = a.getCode();
String bs = b.getCode();
return as.compareTo(bs);
}
}
static class SortByName implements Comparator<ObjectA> {
public int compare(ObjectA a, ObjectA b) {
String as = a.getName();
String bs = b.getName();
return as.compareTo(bs);
}
}
// then in service:
List<Integer> idsPreferred = new ArrayList<>();
List<ObjectA> listObj = new ArrayList<>();
idsPreferred = .... add preferred ids;
listObj = .... add objects;
listObj.sort(new SortByCode()).thenComparing(new SortByName());
With this i sort by code and by name - but i need to add the sorting by the first list - I need the elements that have an id contained in the List to come before the others.
I suppose something like this using chained comparing by extracted key:
listObj.sort(Comparator.comparing(o -> !idsPreferred.contains(((ObjectA) o).getId()))
.thenComparing(o -> ((ObjectA) o).getId())
.thenComparing(o -> ((ObjectA) o).getCode())
.thenComparing(o -> ((ObjectA) o).getName()));
or
listObj.sort(Comparator.comparing(ObjectA::getId,
(id1,id2)-> {if (!((idsPreferred.contains(id1))^idsPreferred.contains(id2)))
return 0;
else return (idsPreferred.contains(id2))?1:-1;})
.thenComparing(ObjectA::getId)
.thenComparing(ObjectA::getCode)
.thenComparing(ObjectA::getName));
The solution will involve 2 steps-
check id of objects from second list, which are present in first list.
Sort the contained objects using either of the solutions suggested- How to sort List of objects by some property
I am trying to create objects by using a list of Strings that will populate their fields. For example I have the list of strings, Note that the values repeat after every 3. i.e. id, name , address.
List<String> myList = "Id1", "name1", "address1", "Id2", "name2", "address2";
I would like to dynamically create a number of Person Objects (shown below) using this list
Person object:
public class Person {
private String id;
private String name;
private String address;
public Person() {
}
public Person(String id, String name, String address) {
this.id = id;
this.name = name;
this.address = address;
}
//standard getters and setters
}
What I want to do is have a method that will take the list of strings as an input and then create the objects dynamically. How could I best do this?
I know that I could do the following if I knew that I was definitely populating 2 objects, but the problem is that there may be more or less.
public List<Person> createObjectsFromStringList(List<String> list){
List<person> personList = new Arraylist<>();
Person person1 = new Person(list.get(0), list.get(1), list.get(2));
Person person2 = new Person(list.get(3), list.get(4), list.get(5));
personList.add(person1);
personList.add(person2);
return personList;
}
A simple for loop can do the work:
public List<Person> createObjectsFromStringList(List<String> list) {
List<person> personList = new Arraylist<>();
//We use < size-2 here because we access 2 indeces ahead of x in this loop
for(int x=0; x<list.size()-2; x+=3) {
personList.add(new Person(list.get(x), list.get(x+1), list.get(x+2));
}
return personList;
}
At first glance, I feel like having the different field values across one List is a sign of a poor code structure, but maybe you're already stuck with this List as-is.
Edit:
Now let's suppose you want a partial Person based on the number of remaining elements. Supposing they are still in the same order, you could modify this method to check the validity of the current index for each field:
public List<Person> createObjectsFromStringList(List<String> list) {
List<person> personList = new Arraylist<>();
int size = list.size();
//Now we remove the "-2" from size check because we will handle this ourselves
for(int x=0; x<size; x+=3) {
String id = list.get(x); //Obviously valid
String name = x+1 < size? list.get(x+1) : null;
String address = x+2 < size? list.get(x+2) : null;
personList.add(new Person(id, name, address);
}
return personList;
}
We're using the ternary operation ? ... : null here, so if we run out of elements we set the associated Person field to null instead of using an out-of-bounds index.
You can use recursion
public List<Person> createObjectsFromStringList(List<String> list){
List<person> personList = new Arraylist<>();
for(int i=0; i<list.size(); i++){
personList.add(new Person(list(i),list(i+1),list(i+2)));
i+=2;
}
return personList;
}
Notice that restructuring your list would me much better. make it like this:
List<String> myList = "Id1_name1_address1", "Id2_name2_address2";
Or even use different lists (it is much better). If you change your list structure as above then change the code to this :
public List<Person> createObjectsFromStringList(List<String> list){
List<person> personList = new Arraylist<>();
for(int i=0; i<list.size(); i++){
String[] info= list(i).split("_"); // this will give u a 3element array of yout info IdX nameX addressX
personList.add(new Person(info(0),info(1),info(2)));
}
return personList;
As you want to access your elements sequentially you should use java.util.LinkedList in such loop
for(true)
if(linkedList.size()>=3){
Person person= new
Person(linkedList.removeFirst(),linkedList.removeFirst(),linkedList.removeFirst());
personList.add(person);
}
else break;
But ArrayList and its get method is good for random access by index which is not your case
If you use java 8 you can try something like this:
public List<Person> createObjectsFromStringList(List<String> list) {
//partition by 3 and list.size.
Map<Integer,List<Integer>> map = IntStream
.range(0,list.size())
.boxed()
.collect(Collectors.groupingBy(e->(e)/3));
List<Person> personList = new ArrayList<>();
map.entrySet().forEach(e->{
List<String> per= e.getValue();
Person p = new Person(per.get(0),per.get(1),per.get(2));
personList.add(p);
});
return personList;
}
I have a list of Visit objects, now I want to build another list containing available hours for given day;
public class Visit {
private int id;
private Date date;
private Time time;
private Pet pet;
private Vet vet;
this is the array String[] containing all visit hours:
public class VisitTime {
private static final String[] visitTime =
{"09:00:00","09:30:00","10:00:00","10:30:00","11:00:00","11:30:00","12:00:00",
"12:30:00","13:00:00","13:30:00","14:00:00","14:30:00","15:00:00","15:30:00","16:00:00","16:30:00"};
so now Im getting from Db list of visits (each visit has defined time), and checking if there is any other free time to schedule a visit.
I have written two methods to do so, one with iteration second with streams, both working as expected.
What I'm asking is how can I rebuild this method to NOT use terminal method twice.
public List<String> getHoursAvailable12(int vetId, String date){
List<Visit> visitList = getVisitByVetIdAndDate(vetId, date);
List<String> hoursAvailable = new ArrayList<>(Arrays.asList(VisitTime.getVisittime()));
List<String> hoursTaken = visitList.stream().map(Visit::getTime).map(Time::toString).collect(Collectors.toList());
return hoursAvailable.stream().filter(x -> !hoursTaken.contains(x)).collect(Collectors.toList());
}
and here is old-school method with collections:
public List<String> getHoursAvailable(int vetId, String date){
List<Visit> visitList = getVisitByVetIdAndDate(vetId,date);
ArrayList<String> hoursAvailable = new ArrayList<>(Arrays.asList(VisitTime.getVisittime()));
for(Visit x : visitList){
{
String time = x.getTime().toString();
if(hoursAvailable.contains(time)) hoursAvailable.remove(time);
}
}
return hoursAvailable;
}
You can try this. You get some benefit here, contains is faster in HashSet compared to List
public Set<String> getHoursAvailable(int vetId, String date){
List<Visit> visitList = getVisitByVetIdAndDate(vetId,date);
Set<String> hoursAvailable = new LinkedHashSet<>(
Arrays.asList(VisitTime.getVisittime()));
visitList.stream()
.map(Visit::getTime)
.map(Time::toString)
.forEach(vt-> hoursAvailable.removeIf(s->s.equals(vt)));
return hoursAvailable;
}
I need a Data Structure that will allow me to store at least 2 pieces of data per item. I want the items to be store in the order they were inserted in.
Example:
Insert (xyz, string) ... insert (789, number)
System.out.println( dataStruct );
will print out (xyz, string) then (789,number)
If possible, please show some sample codes. Thank you!
public class Store {
String str1;
String str2;
public Store(String string1, String string2) {
str1 = string1;
str2 = string2;
}
public static void main(String[] args) {
Store[] s = new Store[10]; // size
for (int i = 0; i < s.length; i++) {
s[i] = new Store("A", "B");
System.out.println(s[i].str1);
System.out.println(s[i].str2);
}
}
}
I think this is what you are searching for . This is C like structure. Try this.
This will help you to insert more than 2 piece of data per item by just doing little changes. And order will be maintained too.
The below code can be your data structure :
List<Item> list;
class Item {
public String desc;
public Integer val;
void insert(String desc,Integer val){
this.desc = desc;
this.val = val;
}
void insert(Integer val,String desc){
insert(desc,val);
}
}
You can use a Hashtable or a List
Example:
Hashtable<Integer,String> hTable=new Hashtable<Integer,String>();
//adding or set items in Hashtable by put method key and value pair
hTable.put(new Integer(2), "Two");
hTable.put(new Integer(1), "One");
hTable.put(new Integer(4), "Four");
hTable.put(new Integer(3), "Three");
hTable.put(new Integer(5), "Five");
Take a look at some Java structures.
EDIT
In order to keep the insertion order one can use a LinkedHashSet or LinkedHashMap
This will somehow fill the requirement,you can also use parameters of the type in the constructors of HashMap.
HashMap map= new HashMap();
List<HashMap> virtualDs= new ArrayList<HashMap>();
I am trying to parse a String into a few variables. The String could contain these 4 tokens: "name, size, age, gender" but they don't all have to be there. Examples of possible Strings.
Example 1. "name:T-rex;"
Example 2. "name:T-rex;size:8;"
Example 3. "name:T-rex;age:4;gender:female"
I tried to do this:
private String name;
private String size;
private String age;
private String gender;
private String parse(String data)
{
String [] parts = data.split(";");
name = parts[0];
size = parts[1];
age = parts[2];
gender = parts[3];
}
But that only works if the String data contains all 4 tokens. How can I solve this problem? I really do need the 4 variables.
The best way is to parse the string into key/value pairs and then call a method that sets them by key:
/**
* Set field based on key/value pair
*/
private void setValue(String key, String value) {
switch(key) {
case "name": {
this.name = value;
break;
}
case "age" : {
this.age = value;
break;
}
//...
}
}
And call it in a programmatic way:
String[] k = "name:T-rex;age:4;gender:female".split(";");
for(String pair: k) {
String[] a = pair.split(":");
setValue(a[0], a[1]);
}
This allows you to be flexible, even to allow some keys to be missing.
Use the magic of hashmaps.
First, split the properties:
String[] parts = inStr.split( ";" );
List<String> properties = Arrays.asList(parts);
Then get name value pairs:
HashMap<String,String> map = new HashMap<String,String>();
Iterator<String> iter = properties.iterator();
for (String property : properties) {
int colPosn = property.indexof(":");
// check for error colPosn==-1
map.put( property.substring(0, colPosn), property.substring(colPosn+1) );
}
Now you can access the properties out of order, and/or test for inclusion like tis:
if(map.containsKey("name") && map.containsKey("age")) {
// do something
String name = map.get("name");
String age = map.get("age");
...