ArrayList as Archive - java

My task is:
The program should read items from the user. When all the items from the user have been read, the program prints the information of each item.
For each item, its identifier and name should be read. If the identifier or name is empty, the program stops asking for input, and prints all the item information. Modify the program so that after entering the items, each item is printed at most once. Two items should be considered the same if their identifiers are the same (there can be variation in their names in different countries, for instance).
If the user enters the same item multiple times, the print uses the item that was added first.
I have done the code below, but it will still add items with the same identifier.
Why? How can I fix it?
import java.util.ArrayList;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
ArrayList<String> itemsName = new ArrayList();
ArrayList<String> itemsIdentifier = new ArrayList();
while(true){
System.out.println("Identifier? (emppty will stop)");
String identifier = scanner.nextLine();
if( identifier.isEmpty()){
break;
}
System.out.println("Name? (emppty will stop");
String name = scanner.nextLine();
if(name.isEmpty()){
break;
}
if(!(itemsIdentifier.contains(identifier))){
itemsIdentifier.add(identifier);
}
if(!(itemsName.contains(name))){
itemsName.add(name);
}
}
System.out.println("==Items==");
int j = 0;
for(String i: itemsIdentifier){
System.out.println(i + ": "+ itemsName.get(j));
j++;
}
}
}

I think the problem with your code is that you are adding name into itemsName list even when you are not adding identifier into itemsIdentifier list in the following lines
if(!(itemsIdentifier.contains(identifier))){
itemsIdentifier.add(identifier);
}
if(!(itemsName.contains(name))){
itemsName.add(name);
}
Ideally shouldn't you either add both name and identifier or don't add any?

You have a while(true) loop which will keep going indefinitely, you are breaking the loop only if the user input is empty, but you are not doing anything when the lists already contain an identifier more than once. (You are adding to the list if you have a unique identifier).
EDIT
I have other misgivings on the code above (I am assuming that this is an assignment), but since I do not know if you built this on top of what the lecturer gave you, I can only speculate. Some thoughts on the code above:
You could create your own Record object.
As per the instructions, you would need to override the equals method.
Instead of having two lists, you would have only 1 list of type Record.

Try something like this:
if(!(itemsIdentifier.contains(identifier))) {
itemsIdentifier.add(identifier);
itemsName.add(name);
}
In your code, if the id is already in the list, the name could still be added...

You only need to check whether the identifier is similar or not. The name similarity condition is not required. As long as the identifiers are different( though they have the same name), you still add them to the itemsIdentifier and itemsName. On the other hand, if the identifiers are identical, there is no need to run a check on the similarity of the name.

Related

Java Load all strings from file into a Set data structure with (key=string, value=line number)

I've been trying to implement a Set data structure with key, value.
I have a txt file (EOL) have a String, line number something like this:
Adam,1
Mary,2
Michael,3
My goal is store this key-value inside a Set.
Here is my code:
public class Main {
public static void main(String[] args)throws Exception
{
Scanner scanner = new Scanner(new FileReader("C:\\Users\\musti\\Desktop\\demo.txt"));
HashMap<String,Integer> mapFirstfile = new HashMap<String,Integer>();
while (scanner.hasNextLine()) {
String[] columns = scanner.nextLine().split(",");
mapFirstfile.put(columns[0],Integer.parseInt(columns[1])); }
// HashMap sıralı yazdırmaz, LinkedHashSet sıralı tutar, ama ekstradan linkedlist lazım.
System.out.println(mapFirstfile);
System.out.println(mapFirstfile.keySet());
System.out.println(mapFirstfile.values());
Set<HashMap> setFirstfile = new HashSet<HashMap>();
}
This is not an answer actually, but too long for comment...
First of all, Set is a structure of unique (in regards to equals()) values.
So your code above actually uses the correct structure Map where you map String to a number (Integer).
Question 1
Is the number needed, is it in the file? You can calculate it from input
Adam
Mary
Michael
we know, that Adam is on a first line...
edit 1: You can use counter which you will increment every time you enter the loop. There is nothing in Java API to do that for you...
Question 2
In your question, I'm missing information about what is not working... What is your expectation that is not true?
Question 3
What in case of duplicates?
Alfa
Bravo
Alfa
Is it ok, that on the 3rd line you remap Alfa to 3?
Question 4
What is your motivation to use Set?
As I wrote in Set contains "single" items. If your item contains several fields, you can wrap in in an Object, but I do not see the benefit...
Something like
class Item {
String line;
int lineNumber;
// TODO: 1 add constructors
// TODO: 2 add getter & setters
// TODO: 3 implement equals() and hashCode()
}
and add it to Set like this:
Set mySet = ...
mySet.add(new Item(line, counter)); // you need to add such constructor

Multiple List<String> in one line

I need to display multiple list arrays in one line through the for loop - so basically I need to count them as well.
Example:
Here is my code:
List<String> name = new ArrayList<String>();
List<String> number = new ArrayList<String>();
name.add("Tommy"); // Test name
name.add("Tom"); // Test name 2
number.add(new String("123-456-7890")); // Test phone number
number.add(new String("098-765-4321")); // Test phone number 2
for (String d:name) {
System.out.print(d);
}
for (String b:number) {
System.out.println(b);
}
And here is my output with my code:
Sorry if this question was duplicated, if it is, I will delete my question right away but for now I haven't fount anything like this.
Thank you.
I think in this case you are better off using a Map, which allows you more flexibility and better control over the entries:
import java.util.HashMap;
import java.util.Map;
/**
* Created by dlcol_000 on 3/19/2016.
*/
public class MapExample {
public void execute(){
Map<String,String> phoneDirectory = new HashMap<>();
phoneDirectory.put("Tommy","123-456-7890");
phoneDirectory.put("Tom", "098-765-4321");
//Now you can do things like, look up the phone number for a person:
String tomsPhone = phoneDirectory.get("Tom");
System.out.println("Toms' phone number is: " + tomsPhone);
//Or you can print the contents of the phone directory
System.out.println("The phone directory contains: " + phoneDirectory);
//Or you can iterate over all people in the directory printing their numbers
for(String person: phoneDirectory.keySet()){
System.out.println(person + ": " + phoneDirectory.get(person));
}
}
public static void main(String... args){
new MapExample().execute();
}
}
Which gives the following output:
Toms' phone number is: 098-765-4321
The phone directory contains: {Tom=098-765-4321, Tommy=123-456-7890}
Tom: 098-765-4321
Tommy: 123-456-7890
You are printing complete the name list and then the number list, you should instead intercalate/alternate and print one from each list for every iteration
final List<String> name = new ArrayList<String>();
final List<String> number = new ArrayList<String>();
name.add("Tommy"); // Test name
name.add("Tom"); // Test name 2
number.add(new String("123-456-7890")); // Test phone number
number.add(new String("098-765-4321")); // Test phone number 2
for (int i = 0; i < name.size(); i++) {
System.out.println(name.get(i) + "\t\t" + number.get(i));
}
at the end I will suggest you as comment above to define a Class "ContactPerson" and override the toString method.
With that approach you will get it faster and safer
It really depends on what you want to use your objects for.
One important aspect is that one should separate concerns. In your case:
there is a concern about "persons"; where each person probably has one name; and one ... or maybe several (!) phone numbers
there is a concern on how certain information is modeled internally. Of course, you can think of a phone number as a simple string with numbers. But you could also design a whole class that holds phone numbers.
there is a concern on how certain information is displayed.
Based on that, you could the following for starters:
create a class "Person" that has two fields; a String for the name; and a String for the phone number
override the toString() method that contains both name and phone number
And all of a sudden, when iterate your list of Person objects and call System.out.println(person.toString()) for each person; you have nicely formatted output.
My key message to you: understand that there are plenty of choices; and shouldn't stop on the first "working" version; but play around ...

how to search an array using user input through a console menu (Java)

I'm working on a program that will allow a user to use a console menu to input various things into an array.
Input instances of the class student into the array which I have done and works.
Create instances of course details which I have also done.
And search the array for a particular students details. If a student with this name exists, it will print all of their details that are stored in the array and if not will throw up a message saying something like "Student not on Course".
I'm just assuming student names are unique as I only need to store 20 of them. I have created this method so far which doesn't seem to be working. I think I need to use a for loop instead of binarySearch but I'm not quite sure how to do that as no videos or posts seem to show how to use this loop with a String and a Scanner.
This is the method so far:
public static void Search()
{
String studentName;
#SuppressWarnings("resource")
Scanner searchScanner = new Scanner(System.in);
System.out.println ("Type Student Name to Search");
studentName = searchScanner.nextLine();
int FoundName;
Arrays.sort(Students);
FoundName = Arrays.binarySearch(Students, studentName);
if (FoundName > -1)
{
System.out.println("FoundName is" + Students[FoundName]);
} else
{
System.out.println("Student not found");
}
}
Any help with this would be greatly appreciated, you would be helping a lowly noob out very much :)
If you prefer to do a sequential search, you can use a for loop like this:
private void Search(){
// Create a scanner for input, and get the name for search
Scanner inputScanner = new Scanner(System.in);
System.out.println("Type student name for search:");
String studentName = inputScanner.nextLine();
// use for loop to search array.
for(int i = 0; i < studentArray.length; i++){
if(studentArray[i].getName().equals(studentName)){
// If student was found, print his details and return from this function.
System.out.println(studentArray[i]);
return;
}
}
// If we reach this point, it means the student was never found in the for loop.
System.out.println("Student not found.");
}
A couple things to note:
In your question, you're comparing a student object with a string. The difference in types alone is enough to make the binary search return false, so you will never get a match.
In my loop, I am assuming the array holds Student objects, so I call getName() on the student object to compare the two strings, so I will get a match if one exists.
Printing the student object itself will not just print values, you need to override toString() if you haven't yet.
First of all don't do the SuppressWarnings. It's a bad practice and not good when you are beginning to learn to start with bad practices.
I would use instead of the binarySearch for your case, just use the contains method in a list, like this:
List <String> list = new ArrayList();
list.add("one");
list.add("two");
if (list.contains("two")) {
System.out.println("true");
}
In addition no need to sort the array : ).

Creating a for loop to do a to.String to my array list

Im currently making a shopping store application, I have 6 classes. 1 for products where it defines the fields for products in the store, another for the shopping basket, one for the GUI and the rest for listeners.
I need to be able to run a method that runs through an array list and running the to.String method on it and returning it as String. Here is what I have at the moment,
private ArrayList<OrderItem> basket = new ArrayList<OrderItem>();
public String createArrayText () {
for (int i = 0; i < OrderItem.size(); i++){
if (i == OrderItem.size() - 1){
return ordersText ;
}
}
}
ordersText is a variable I made at the top of my shopping cart class.
This was my first start at it however I'm getting a error on the .size and obviously missing some key components.
One thing Extra is that each item created is added to the array list, each item has a unique order number.
Arrays.toString(basket);
Is that what you're looking for? If not, you need to explain a little better.
You generally speaking loop over a List like this (Java 7, it's called enhanced for loop):
for (TYPE TEMP_NAME : COLLECTION) {
}
That's the overall syntax. TYPE is the type of item in the list, yours are Object's in the given code. TEMP_NAME is the temporary name you want each entry to be referred as. COLLECTION is the list/array/stack/queue or other Collection.
Concretely:
for (Object o : basket) {
// if basket contains 10 entries the line will run 10 times. each new run contains a different object with name o
}
Normally when building strings it's preferred to use StringBuilder. We can skip that as it's "only" performance that you gain from it. We'll do it with a regular String. So:
Create an empty string that will get longer and longer
Loop the collection/array/list
Append each object's .toString() to the string from 1)
e.g.
String myReturnString = "";
for (Object o : basket) {
myReturnString = myReturnString + " // " + o.toString();
}
return myReturnString;
Notes:
Your loop with an index is fine. You can do it that way too, if you want to.
The line of code that appends the string has a " // " separator between each entry. You can pick whatever you like. You can also simplify it to be myReturnString += " // " + o.toString();

Why is my counter incrementing in loop, but returns zero?

With my current project, I have to keep a counter of the number of insertions into a TreeMap<String, TreeSet<Song>>. The project is to run search of individual words in a string, in this case, song lyrics. I have three tests to determine the course of the map insertions, and my algorithm goes:
test if word has more than one character and is not a common word
if map already contains the word as a key, test if set already contains the song
if true, increment insertion counter
if map doesn't contain word as key
make new node, add song to set
increment counter
I declare the counter as private double insertions; as a class variable.
It is initialized in the constructor:
public SearchByLyricsWords(SongCollection sc) {
this.songs= sc.getAllSongs();
buildSongMap();
insertions=0;
totalReferences=0;
averageReferences=0;
}
The buildMap method:
for (String word:currentLyrics) {
if (word.length()>1 && !commonWords.contains(word)) {
if (lyricWords.containsKey(word)) {
if (!lyricWords.get(word).contains(song))
insertions++; //this is a non-duplicate song in the set
lyricWords.get(word).add(song);
} else {
TreeSet<Song> songSet= new TreeSet<Song>();
songSet.add(song);
lyricWords.put(word, songSet);
keyWords.add(word);
insertions++;
}
//System.out.println(word+" added");
}
} //end loop through string
Why is a class variable that is modified in a method, not then giving the correct value in another method?
Try
public SearchByLyricsWords(SongCollection sc) {
this.songs= sc.getAllSongs();
insertions=0;
totalReferences=0;
averageReferences=0;
buildSongMap();
}
It looks like you are setting the variable to zero right after calling the buildsongmap function.
As has already been mentioned, it's a matter of initialization in the constructor. One other thing: in your buildSongMap method, you are adding the song to the map regardless of whether or not it already contains it. Although you're using a Set, which will prevent duplicates, I think it's more readable to only perform the add in the case where it already does not exist.
if (!lyricWords.get(word).contains(song)) {
insertions++;
lyricWords.get(word).add(song);
}

Categories

Resources