Here I have created a class:
class book{
String book_nm;
String author_nm;
String publication;
int price;
book(String book_nm,String author_nm,String publication,int price){
this.book_nm=book_nm;
this.author_nm=author_nm;
this.publication=publication;
this.price=price;
}
}
Now I want to search for particular value according to author and book name
ArrayList<book> bk = new ArrayList<book>();
I have created a menu driver using switch case
case 3: System.out.println("Search:"+"\n"+"1.By Book Name\n2.By Author Name");
Scanner s= new Scanner(System.in);
int choice=s.nextInt();
while(choice<3){
switch(choice){
case 1:System.out.println("Enter the name of the book\n");
String name=s.next();
-------
case 2:System.out.println("Enter the name of the author\n");
String name=s.next(); ------
}
}
I know how to find and search for a particular element in ArrayList but not for objects.
Using for loop over ArrayList can solve your problem, it's naive method and old fashioned.
Below is the code for it.
import java.util.ArrayList;
public class HelloWorld{
public static void main(String []args){
String author_name = "abc";
ArrayList<book> bk = new ArrayList<book>();
bk.add(new book("abc", "abc", "abc", 10));
bk.add(new book("mno", "mno", "abc", 10));
bk.add(new book("xyz", "abc", "abc", 10));
ArrayList<book> booksByAuthor = new ArrayList<book>();
for(book obj : bk)
{
if(obj.author_nm == author_name)
{
booksByAuthor.add(obj);
}
}
}
}
class book{
public String book_nm;
public String author_nm;
public String publication;
public int price;
public book(String book_nm,String author_nm,String publication,int price){
this.book_nm=book_nm;
this.author_nm=author_nm;
this.publication=publication;
this.price=price;
}
}
Hope you can get an idea from it.
Below code return a list, based on of your search (filter):
List< Book> result = bk.stream().filter(book -> "booknamehere".equals(book.getBook_nm()))
.filter(book -> "authernamehere".equals(book.getAuther_nm()))
.collect(Collectors.toList());
First there is a new ways (With java 8+) and old way to do this. The new ways will be something like this:
String authorName = s.next();
String bookName = s.next();
List<String> result = bk.stream() // open stream
.filter(book-> book.getBook_nm().equals(bookName) && book.getAuthor_nm().equals(authorName ) )
.collect(Collectors.toList());
Another (old fashioned) way is with for loop:
ArrayList<book> result = new ArrayList<book>();
for(Book book : bk) //By the way always use Big first letter for name of your Class! (Not book but Book)
{
if(book.getBook_nm().equals(bookName) && book.getAuthor_nm().equals(authorName))
{
result.add(book);
}
}
After this you can print in both cases the result list containing the book. But if you will search a lot of this author and book name and you have a lots of elements you can think check the performance. Because every search will loop over the list. Maybe there is better solution using Map ...
Some additional information. It is import if you know if there is always only one element that will be found from the criteria. For example in your case you unique find one book where has name X and author Y. There can not be another book with the same name and author. In such cases you can do like this:
New way (after java 8):
Book res = bk.stream()
.filter(book -> book.getBook_nm().equals(bookName) && book.getAuthor_nm().equals(authorName))
.findFirst()
.get();
old way:
Book result = null;
for(Book book : bk)
{
if(book.getBook_nm().equals(bookName) && book.getAuthor_nm().equals(authorName))
{
result = book;
break;
}
}
This way it is faster when you search one element
Good luck!
Related
Given a list of objects that have a "key" property which is a string, is there any way I can use streams .sorted() method so that it treats the key as an int and uses the key to sort the objects?
Let's use this as an example
public class Book {
public String key;
public String title;
public Book(String key, String title) {
this.key = key;
this.title = title;
}
// Getters and Setters omitted from example but assume they exist
}
Book book1 = new Book("1", "A good book");
Book book2 = new Book("2", "A bad book");
List<Book> bookList = new ArrayList<>();
bookList.add(book2);
bookList.add(book1);
My goal in this case would be to sort the book list using streams and the key property so that book1 becomes the 1st element and book2 becomes the second element.
I have tried something like this but I still seem to get exceptions.
List<Book> sortedList = bookList.stream()
.sorted(Comparator.comparingInt(b -> Integer.parseInt(b.getKey()))
.collect(Collectors.toList());
Does anyone notice anything immediately that would cause this to fail? Any clarification is much appreciated!
Add a getKey() getter to your class to return the key
Add one more closing parenthesis ) to sorted(Comparator.comparingInt(b -> Integer.parseInt(b.getKey()))
But you can also sort bookList in place as follows
bookList.sort(Comparator.comparingInt(b -> Integer.parseInt(b.getKey())));
Note: If you use a constructor of Book(int key, String title) and change the types of key and the getter to int you won't have to parse the String. Then you could do:
bookList.sort(Comparator.comparingInt(Book::getKey));
I have an ArrayList of objects called Student.
I want to filter this list and return a single Student object only based on hierarchical conditions.
The conditions are as follows:
Select the first COMP student.
If none are returned, select an ECON student.
If none are returned, select a AGRI student.
... etc.
In my design, I have hard coded this - but maybe it can use a sorted Set or List or something.
My current code works, but seems messy, and will grow quite large if more conditions are introduced.
I need help with the Student filterStudent(List<Student> studentList) method. How to do this in fewer lines of code maybe or method chaining. And how to introduce a sorted Set of Enums that can be filtered based on preference (Example, COMP first, if empty, then ECON next, etc. Stop filtering if one is found).
Code:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
class Student {
private final int stNumber;
private final String stModule;//...more fields
public Student(int stNumber, String stModule) {
this.stNumber = stNumber;
this.stModule = stModule;
}
public int getStNumber() {
return stNumber;
}
public String getStModule() {
return stModule;
}
#Override
public String toString() {
return "Student{" +
"stNumber=" + stNumber +
", stModule='" + stModule + '\'' +
'}';
}
}
enum Module {
COMP("Computers"),
ECON("Economics"),
AGRI("Agriculture"),
PHYS("Physics"); //...very large list
private String moduleName;
public String getModuleName() {
return moduleName;
}
Module(String moduleName) {
this.moduleName = moduleName;
}
}
public class Question {
public static void main(String[] args) throws Exception {
//These lists can be any size and contain any information
List<Student> studentListOne = Arrays.asList(
new Student(41, "Economics"),
new Student(45, "Computers")
);
List<Student> studentListTwo = Arrays.asList(
new Student(11, "Physics"),
new Student(23, "Agriculture"),
new Student(86, "Physics"),
new Student(34, "Economics")
);
List<Student> studentListThree = new ArrayList<>();
System.out.println(filterStudent(studentListOne));
System.out.println(filterStudent(studentListTwo));
System.out.println(filterStudent(studentListThree)); //exception
}
/**
* Rules are: Choose the first instance of a COMP student.
* If the list is empty, choose a ECON student.
* If the list is still empty, choose a AGRI student.
*
* #param studentList
* #return Student
*/
public static Student filterStudent(List<Student> studentList) throws Exception {
Optional<Student> selectedStudent;
selectedStudent = studentList.stream().filter(student -> student.getStModule().equalsIgnoreCase(Module.COMP.getModuleName())).findFirst();
if (selectedStudent.isPresent()) {
return selectedStudent.get();
}
selectedStudent = studentList.stream().filter(student -> student.getStModule().equalsIgnoreCase(Module.ECON.getModuleName())).findFirst();
if (selectedStudent.isPresent()) {
return selectedStudent.get();
}
selectedStudent = studentList.stream().filter(student -> student.getStModule().equalsIgnoreCase(Module.AGRI.getModuleName())).findFirst();
if (selectedStudent.isPresent()) {
return selectedStudent.get();
}
throw new Exception("No student found matching criteria");
}
}
You can rewrite your current method with a loop:
for (Module mod : Arrays.asList(Module.COMP, Module.ECON, Module.AGRI)) {
String subj = mod.getModuleName();
Optional<Student> selectedStudent = studentList.stream().filter(student -> student.getStModule().equalsIgnoreCase(subj)).findFirst();
if (selectedStudent.isPresent()) {
return selectedStudent.get();
}
}
throw new Exception(...);
If you want to avoid iterating the list multiple times, you can declare a Comparator<Student>:
Map<String, Integer> ordering = Map.of(Module.COMP.getModuleName().toLowerCase(), 0, Module.ECON.getModuleName().toLowerCase(), 1, Module.AGRI.getModuleName().toLowerCase(), 2);
ToIntFunction<Student> studentOrdering = student -> ordering.getOrDefault(student.getModuleName().toLowerCase(), ordering.size());
Comparator<Student> comparator = Comparator.nullsLast(Comparator.comparingInt(studentOrdering));
A simple solution would then be to use Stream.min:
Optional<Student> student = studentList.stream().min(comparator);
and this is probably fine. If you want to do it with a more explicit list, you can stop as soon as you find a COMP student:
Student best = null;
for (Student student : studentList) {
int comp = comparator.compare(best, student);
if (comp > 0) {
best = student;
int studentOrder = studentOrdering.apply(student);
if (studentOrder == 0) {
// Can't find a better student, so fast break.
break;
}
}
}
if (best != null) {
return best;
}
throw new Exception(...);
One thing you can do to support a dynamic list and order of selected modules is to filter the list, sort it and then pick the first element:
public static Student filterStudent(List<Student> studentList, List<String> moduleOrder)
throws Exception {
return studentList.stream().filter(s -> moduleOrder.contains(s.getStModule()))
.min(Comparator.comparingInt(student -> moduleOrder.indexOf(student.getSModule())))
.orElseThrow(() -> new Exception("No student found matching criteria"));
}
And to execute your current logic, you can call it with the student list and something like List.of(Module.COMP.getModuleName(), Module.ECON.getModuleName(), Module.AGRI.getModuleName()) as second argument.
This will avoid the repeated iterations over the list. But I'm assuming that the moduleOrder list is small, with a handful of elements as in your example (it is searched a few times for filtering and for sorting)
how to implement Java Based Auto suggestion. suppose I have different types of data like firstName, rollNumber, address.
My first requirement is like if user enter first character on text box, then result should be sorted on natural order based on firstName and 10 results should be display.
after space if use enter second character and if it is numbere then RollNumber else lastName should be sorted on natural order as ascending.
or if user type third character then Address should be display on ascending order. there should be no database, you don't have to implement Solr or other api. how to implement on pure Java.
here I did not implement the text-box,but I Just took an example to demonstrate
import java.util.*;
import java.lang.*;
import java.io.*;
// A class to represent a student.
class Student {
int rollno;
String name;
String address;
// Constructor
public Student(int rollno, String name, String address) {
this.rollno = rollno;
this.name = name;
this.address = address;
}
// Used to print student details in main()
public String toString(){
return this.rollno + " " + this.name +
" " + this.address;
}
}
class Sortbyroll implements Comparator<Student> {
// Used for sorting in ascending order of rollno
public int compare(Student a, Student b) {
return a.rollno - b.rollno;
}
}
class Sortbyname implements Comparator<Student> {
// Used for sorting in ascending order of name
public int compare(Student a, Student b) {
return a.name.compareTo(b.name);
}
}
// Driver class
class Main {
public static void main (String[] args) {
ArrayList<Student> ar = new ArrayList<Student>();
//here I have thousand student are inserted into
//simple collection.
ar.add(new Student(111, "bbbb", "london"));
ar.add(new Student(131, "aaaa", "nyc"));
ar.add(new Student(121, "cccc", "jaipur"));
System.out.println("Unsorted");
for (int i=0; i<ar.size(); i++) {
System.out.println(ar.get(i));
}
//collection sorted by rollno
Collections.sort(ar, new Sortbyroll());
System.out.println("\nSorted by rollno");
for (int i=0; i<ar.size(); i++) {
System.out.println(ar.get(i));
}
//sort by Name
Collections.sort(ar, new Sortbyname());
System.out.println("\nSorted by name");
for (int i=0; i<ar.size(); i++) {
System.out.println(ar.get(i));
}
}
}
First of all your question is incomplete and misleading. It does not describes the requirement properly. But overall what I assume
You want Google like (?) suggester in your text box
It does not tell any specific things. What about your front end ? How about your data ?
Any way I think you just wanted to have a console like application where you will give partial String as input and your method will guess the Rest of String as an assumption from your dummy data. Am I right ?
If that is the thing you were looking for then I just sketched a demo code below
static List<String> query(String queryStr, List<Student> list) {
List<String> suggestion = new ArrayList<>();
list.forEach(std -> {
if (isMatched(queryStr, String.valueOf(std.getRoll()))) {
suggestion.add(String.valueOf(std.getRoll()));
}
if (isMatched(queryStr, std.getName())) {
suggestion.add(std.getName());
}
if (isMatched(queryStr, std.getAddress())) {
suggestion.add(std.getAddress());
}
});
return suggestion;
}
private static boolean isMatched(String query, String text) {
return text.toLowerCase().contains(query.toLowerCase());
}
And what does this code do ? It actually takes the Partial String that the user input so far and your List<Student> as parameters. Then it iterates over the list and matches for all field for partial match. If any field matches the query it add that value in the suggestion list. In the main you can do like this :
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
list.add(new Student(101, "Abc ghi", "USA"));
list.add(new Student(102, "DEF", "UST"));
list.add(new Student(103, "Ghi ab", "DSjkD"));
list.add(new Student(104, "jKL ut", "USN"));
list.add(new Student(105, "MNP", "TSA101"));
list.add(new Student(106, "UTC ABC", "ESA"));
List<String> sugg = query("01", list);
sugg.forEach(System.out::println);
}
and you will find the console printed like :
101
TSA101
Does it make sense ? it might not be your whole confusing requirements. But I think you got the idea. You can exploit this to address your own requirements. You could further imply your sorting logic or any kind of filters to it. It should not be that tough thing.
But you should be concerned that with large number of collection or complex associated objects this would not suffice. Real world application does not work this straight forward. You might need lot of other things to consider like memory, i/o and execution time.
Good Luck!
Do refer https://github.com/nikcomestotalk/autosuggest/
This implementation is in java based on Patricia trie and Edit distance algorithm.
Some salient features of this application is
Auto correction of keywords
Bucket support for sorting and personalization support.
Filtering support.
Limit support.
Build in http server.
Blazing fast search.
And you all are welcome for feedback
Solr/Lucene/Elastic will not give freedom to choose algorithm and personalization support.
You can use a Trie data structure for autosuggestion implementation and the time complexity would be O(word_length) for insert and search.
Apache commons provides implementation "org.apache.commons.collections4.Trie"
example:
Trie<String, String> trie = new PatriciaTrie<>();
trie.put("abcd", "abcd");
trie.put("abc", "abc");
trie.put("abef", "abef");
SortedMap<String, String> map = trie.prefixMap("ab");
map.forEach((k, v) -> {
System.out.println(k + " " + v);
});
I have a huge problem with my code:
public class BookStore
{
private ArrayList<Book> books;
}
/**
* This method takes the author's name as a String parameter and returns an
* arraylist of all the books written by that author. It uses a while loop
* and an iterator, locates the books written by that author (case-insensitive)
* and adds them to another arraylist.
*/
public ArrayList<Book> getBooksByAuthor(String authorName){
ArrayList<Book> getBooksByAuthor = new ArrayList<Book>();
Iterator<Book> aBook = books.iterator();
while(aBook.hasNext()){
Book aBookd = aBook.next();
if (authorName.equalsIgnoreCase(aBookd.getAuthor())){
books.add(getAuthor());
books.addAll(getBooksByAuthor);
}
}
return getBooksByAuthor.size();
}
Those 3 lines
books.add(getAuthor());
books.addAll(getBooksByAuthor); and the
return getBooksByAuthor.size();
I'm pretty sure that they are completely wrong. I tried different ways to do it ,but it didn't work. I really don't understand how to do that. Could someone help me?. Thank you for your time!
I'm fairly certain you wanted to add the book(s) with matching author's name to a new List. Something with an implicit iterator using a for-each loop
List<Book> al = new ArrayList<>();
for (Book book : books) {
if (authorName.equalsIgnoreCase(book.getAuthor())) {
al.add(book);
}
}
return al;
or using an explicit Iterator like
List<Book> al = new ArrayList<>();
Iterator<Book> iter = books.iterator();
while (iter.hasNext()) {
Book book = iter.next();
if (authorName.equalsIgnoreCase(book.getAuthor())) {
al.add(book);
}
}
return al;
is there any specific need for the iterator and a while-loop instead of a foreach loop?
what (i think) you'd like to achive is in normal language is: we have an empty collection/list as result. for each book in the list of books, check if the author has an equal name to the given name - if the names are equal, we add the book to the resulting collection/list.
that in code looks like:
public ArrayList<String> getBooksByAuthor(String authorName) {
ArrayList<Book> result = new ArrayList<Book>();
for (Book aBook : books) { //[for each notation in java ][1]
if (authorName.equals(aBook.getAuthor())) {
result.add(aBook);
}
}
return result;
}
if you'd like to use a while loop, read up the foreach/while loop conversion in the this link.
in addition and as mentioned in the comments, your code has some semantic and syntactic errors:
your return type is wrong (int instead of ArrayList)
your class definition closing brace ends before your method definition
you add the author object (probably a string) to your books-collection
you never add any book to your resulting collection
you try to addAll objects of your (empty) collection getBooksByAuthor to your books, instead of adding some/single books to your getBooksByAuthor collection
[1] http://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html
This is a drive method for two other classes. which i posted here
https://codereview.stackexchange.com/questions/33148/book-program-with-arraylist
I need some help for the
private static ArrayList getAuthors(String authors) method. I am kind a beginner. so please help me finish this drive method. or give me some directions.
Instruction
some of the elements of the allAuthors array contain asterisks “*” between two authors names. The getAuthors method uses this asterisk as a delimiter between names to store them separately in the returned ArrayList of Strings.
import java.util.ArrayList;
public class LibraryDrive {
public static void main(String[] args) {
String[] titles = { "The Hobbit", "Acer Dumpling", "A Christmas Carol",
"Marley and Me", "Building Java Programs",
"Java, How to Program" };
String[] allAuthors = { "Tolkien, J.R.", "Doofus, Robert",
"Dickens, Charles", "Remember, SomeoneIdont",
"Reges, Stuart*Stepp, Marty", "Deitel, Paul*Deitel, Harvery" };
ArrayList<String> authors = new ArrayList<String>();
ArrayList<Book> books = new ArrayList<Book>();
for (int i = 0; i < titles.length; i++) {
authors = getAuthors(allAuthors[i]);
Book b = new Book(titles[i], authors);
books.add(b);
authors.remove(0);
}
Library lib = new Library(books);
System.out.println(lib);
lib.sort();
System.out.println(lib);
}
private static ArrayList<String> getAuthors(String authors) {
ArrayList books = new ArrayList<String>();
// need help here.
return books;
}
}
try this
private static ArrayList<String> getAuthors(String authors) {
ArrayList books = new ArrayList<String>();
String[] splitStr = authors.split("\\*");
for (int i=0;i<splitStr.length;i++) {
books.add(splitStr[i]);
}
return books;
}
What I would suggest is to use String.split like here (but keep in mind that this method uses a regex as parameter):
private static ArrayList<String> getAuthors(String authors) {
ArrayList books = new ArrayList<String>();
String[] strgArray = authors.split("\\*");
books.addAll(Arrays.asList(strgArray));
return books;
}
or
private static ArrayList<String> getAuthors(String authors) {
String[] strgArray = authors.split("\\*");
ArrayList books = Arrays.asList(strgArray);
return books;
}
Try this one but actually i do not understant why you remove zero indexed element of ArrayList in for loop.
private static ArrayList<String> getAuthors(String authors) {
ArrayList<String> array = new ArrayList<String>();
String[] authorsArray = authors.split("\\*");
for(String names : authorsArray );
array.add(names);
return array;
}
Take a look at String#split method, this will help you to separate authors by asterisk. This method returns an array so you will need to check how many authors are in this array and then store each of them into the ArrayList.
Here's how you can go about doing it.
Split the authors string you're getting as the method param based on the asterisk symbol. (Using String.split(delim) method)
The resultant string[] array needs to be iterated over using a for loop and each iterated element should be added to your list. (Using List.add(elem) method)
Once done, return that list(you are already doin that).
Now that you know how to do it, you need to implement the code by yourself.