I have a class called Bag2 and it has inner class called Item. Bag2 has variable ArrayList aList and function called "add". It's adding wrong by repeat adding duplicate value.
Here is my code:
import java.util.ArrayList;
public class Bag2 {
public Bag2(){}; // Constructor
/**
* Inner class
*
*/
public class Item implements Comparable<Item> {
String name;
int quantity;
public Item(String name, int quantity) { // Constructor
this.name = name;
this.quantity = quantity;
}
#Override
public String toString() {
return name + " : " + quantity;
}
#Override
public int compareTo(Item o) {
return name.compareToIgnoreCase(o.name);
}
}
public ArrayList<Item> aList = new ArrayList<>();
public void add(String itemName){
Bag2 bag2 = new Bag2();
Bag2.Item item = bag2.new Item(itemName.toUpperCase(), 1);
if (aList.isEmpty()){
aList.add(item);
} else
{
for(int i = 0; i < aList.size();i++){
if (item.compareTo(aList.get(i))==0){
aList.get(i).quantity++;
}else {
aList.add(item); // Built inn add-function
break; // add one time only and the size increases
}
}
}
}
}
And here is my test :
public class Bag2Test {
public static void main(String[] args) {
Bag2 bag = new Bag2();
Bag2.Item[] anArray =
{
bag.new Item("A", 1),
bag.new Item("B", 1),
bag.new Item("C", 1),
bag.new Item("D", 1),
bag.new Item("a", 1),
bag.new Item("F", 1),
bag.new Item("b", 1),
bag.new Item("e", 1),
bag.new Item("a", 1)
};
for (int i = 0; i<anArray.length; i++ ){
bag.add(anArray[i].name); //
}
System.out.println("\nA list contains : ");
for (int i = 0; i<bag.aList.size(); i++) {
System.out.println(bag.aList.get(i));
}
}
}
and output:
A list contains :
A : 3
B : 1
C : 1
D : 1
A : 1
F : 1
B : 1
E : 1
A : 1
Your add function is broken because it can trigger the statement if (item.compareTo(aList.get(i))==0) for one i value and still add it for another value. While there are more elegant and robust solutions for you program including overriding equals()and hashCode() and using a Set instead of a list, that would result in a generic bag implementation and I posted the shortest fix for your problem.
public void add(String itemName)
{
Bag2 bag2 = new Bag2();
Bag2.Item item = bag2.new Item(itemName.toUpperCase(), 1);
if (aList.isEmpty())
{
aList.add(item);
} else
{
boolean existing = false;
for(int i = 0; i < aList.size();i++)
{
if (item.compareTo(aList.get(i))==0)
{
aList.get(i).quantity++;
existing=true;
break;
}
}
if(!existing) {aList.add(item);}
}
}
Let's say you add the following items : A,B,C
now your list is : A:1, B:1, C:1
In your add logic you check if the current item is the same one, otherwise you add the item. So if we now try to add item C again your list will look like this: A:1, B:1, C:1, C:1
This is because you are checking item by item. Before adding the new item you need to check that it does not exist in the ENTIRE list and only then add it. (e.g. When adding C to the above list the first loop iteration (i=0) will execute the code in the else block since C and A are different and C will be added although it does exist in the list)
Related
I want to only change the int value of a specific item in a LinkedList, to a new int value. I would also like to understand the logic of how it is done, not only the code.
p.s I can not change anything, I can only add to the inside of the methods.
Thank you.
For example:
[Green tea, 1] to [Green tea, 2]
The method where this needs to happen
public void changeItemCount(int k, int m){
}
Class where the question is
import java.util.LinkedList;
import java.util.ListIterator;
public class GroceryList {
//this class will create an object that contains a list of Grocery Items
//variable
private LinkedList<GroceryItem> glist; //holds GroceryItems
//constructor: instantiates glist to an empty groceryList
public GroceryList() {
glist = new LinkedList<GroceryItem>();
}
// return number of GroceryItems in glist
public int getSize() {
return glist.size();
}
//return GroceryItem at requested index
public GroceryItem getItem(int k) {
GroceryItem m = glist.get(k);
return m;
}
//add GroceryItem x to end of glist
public void addItem(GroceryItem x) {
glist.add(x);
}
//Remove item at index k from glist
public GroceryItem removeItem(int k ) {
return glist.remove(k);
}
//change item count for k item in glist to m
public void changeItemCount(int k, int m) {
//need help here
}
//Should work as is
public void sortList( ) {
glist.sort(null);
System.out.println("Sorted GroceryList: " + glist);
}
}
other class in relation:
public class GroceryItem implements Comparable<GroceryItem> {
//this class will create items from a Grocery Store and the desired quantity
//variables
private String name; //grocery item name
private int count; // number needed; make sure count is always >= 0
//set count = 1; set name = s in following constructor
//if only a string is passed, default count is set to 1
public GroceryItem ( String s) {
count = 1;
name = s;
}
//constructor
// set name = s and set count = initCount in following constructor
//if a string and an int are passed then we set them to the passed values
public GroceryItem ( String s , int initCount) {
name = s;
count = initCount;
}
//returns the current count
public int getCount() {
return count;
}
//returns a fixed/known amount
public void setCount(int m) {
count = m;
}
public String getName() {
return name;
}
//#Override
public int compareTo(GroceryItem o) {
if( name.compareTo(o.getName() ) < 0) //less than compared item
return -1;
else if (name.compareTo(o.getName()) > 0) //greater than compared item
return 1;
else
return( count - o.count); //duplicated item?
}
//toString method: formatting: [bananas, 3]
public String toString() {
name.toString();
String temp = Integer.toString(count);
String formatt = name + ", " + temp ;
return formatt;
}
}
main driver:
public class GroceryListDriver {
//this class tests the methods of the two other classes
public static void main(String[] args) {
// TODO Auto-generated method stub
//creating 10 items in GroceryItem
GroceryItem items1 = new GroceryItem("banana", 5);
GroceryItem items2 = new GroceryItem("apples", 5);
GroceryItem items3 = new GroceryItem("pea soup", 2);
GroceryItem items4 = new GroceryItem("apples", 3);
GroceryItem items5 = new GroceryItem("wheat bread", 2);
GroceryItem items6 = new GroceryItem("tuna fish", 5);
GroceryItem items7 = new GroceryItem("potatoes", 4);
GroceryItem items8 = new GroceryItem("sourdough bread", 1);
GroceryItem items9 = new GroceryItem("chedadar cheese", 1);
GroceryItem items10 = new GroceryItem("green tea", 1);
//creating groceryList called groceryList
GroceryList groceryList = new GroceryList();
//adding to the list
groceryList.addItem(items1);
groceryList.addItem(items2);
groceryList.addItem(items3);
groceryList.addItem(items4);
groceryList.addItem(items5);
groceryList.addItem(items6);
groceryList.addItem(items7);
groceryList.addItem(items8);
groceryList.addItem(items9);
groceryList.addItem(items10);
//print current list
//groceryList.printGroceryList(null);
//sorting groceryList
//groceryList.sortList();
//change count of green tea to 2
System.out.println(groceryList.getItem(9));
}
}
Try this one:
public void changeItemCount(int k, int m){
GroceryItem item = getItem(k); //just get the item from list
item.setCount(m); //and change the count value
}
I have an item that has a name and a price for it.
Now input for my program contains some list of commands which indicate I can add new item or select an item in the following format:
Add, item-name, item-price --> Adds item-name with price item-price to my list.
Select, , --> select the item name that has lowest price at index k, and prints to output. If multiple items has same price then select the name in ascending order.
Example 1:
Input :
Add, Apple, 4
Add, Ball, 3
Select, ,
Add, Toy, 5
Add, Pen, 1
Select, ,
Output:
Ball, Ball
Explanation:
First we add Apple and Ball. So the items sorted by price [Ball(3), Apple(4)]. Initialize k to 0.
Then Select has appeared. So get item at index k=0 which is Ball. Now increment k to 1 as a selection has occurred.
Then we add Toy and Pen. So the items sorted by price [Pen(1), Ball(3), Apple(4), Toy(5)] . Now k is 1.
Then Select has appeared. So get item at index k=1 which is Ball again. Now increment k to 2 as a selection has occurred.
So output is Ball, Ball.
Example 2:
Input :
Add, Apple, 4
Add, Ball, 3
Select, ,
Select, ,
Add, Toy, 5
Select, ,
Output:
Ball, Apple, Toy
Explanation:
First we add Apple and Ball. So the items sorted by price [Ball(3), Apple(4)]. Initialize k to 0.
Then Select has appeared. So get item at index k=0 which is Ball. Now increment k to 1 as a selection has occurred.
Then Select has appeared. So get item at index k=1 which is Apple. Now increment k to 2 as a selection has occurred.
Then we add Toy. So the items sorted by price [Ball(3), Apple(4), Toy(5)] . Now k is 2.
Then Select has appeared. So get item at index k=2 which is Toy. Now increment k to 3 as a selection has occurred.
So output is Ball, Apple, Toy.
This is the code I tried:
public static void main(String[] args) {
System.out.println(process(Arrays.asList(Arrays.asList("Add", "Apple", "4"), Arrays.asList("Add", "Ball", "3"),
Arrays.asList("Select", "", ""), Arrays.asList("Add", "Toy", "5"), Arrays.asList("Add", "Pen", "1"),
Arrays.asList("Select", "", ""))));
System.out.println(process(Arrays.asList(Arrays.asList("Add", "Apple", "4"), Arrays.asList("Add", "Ball", "3"),
Arrays.asList("Select", "", ""), Arrays.asList("Select", "", ""), Arrays.asList("Add", "Toy", "5"),
Arrays.asList("Select", "", ""))));
}
public static List<String> process(List<List<String>> input) {
List<String> list = new ArrayList<>();
PriorityQueue<Item> pq = new PriorityQueue<>();
int k = 0;
for (List<String> e : input) {
if ("Add".equals(e.get(0))) {
Item a = new Item(e.get(1), e.get(2));
pq.add(a);
} else {
List<Item> sorted = new ArrayList<>();
for (int i = 0; i <= k; i++) {
sorted.add(pq.poll());
}
Item itemAtK = sorted.get(sorted.size() - 1);
list.add(itemAtK.name);
pq.addAll(sorted);
k++;
}
}
return list;
}
}
class Item implements Comparable<Item> {
int price;
String name;
public Item(String name, String p) {
this.name = name;
this.price = Integer.parseInt(p);
}
public int compareTo(Item item) {
int c = price - item.price;
if (c == 0)
c = name.compareTo(item.name);
return c;
}
Here time complexity is I guess n^2*log(n)
How to reduce the time complexity for this code.
Modified code based on stef comments:
public static List<String> process(List<List<String>> input) {
List<String> list = new ArrayList<>();
PriorityQueue<Item> pq = new PriorityQueue<>();
for (List<String> e : input) {
if ("Add".equals(e.get(0))) {
Item a = new Item(e.get(1), e.get(2));
pq.add(a);
} else {
Item itemAtK = pq.poll();
list.add(itemAtK.name);
}
}
return list;
}
Input :
Add, Apple, 4
Add, Ball, 3
Select, ,
Add, Toy, 5
Add, Pen, 1
Select, ,
Expected Output:
Ball, Ball
This program gives wrong output:
Ball, Pen
As someone commented, perhaps what you need is not a PriorityQueue.
Here is an implementation with an unbalanced BST:
public static List<String> process(List<List<String>> input) {
List<String> list = new ArrayList<>();
Item root = null;
int k = 0;
for (List<String> e : input) {
if ("Add".equals(e.get(0))) {
Item a = new Item(e.get(1), e.get(2));
root = Item.insert(root, a);
} else {
Item first = Item.itemAt(root, k);
list.add(first.name);
++k;
}
}
return list;
}
class Item implements Comparable<Item> {
int count;
private Item left;
private Item right;
int price;
String name;
public Item(String name, String p) {
this.name = name;
this.price = Integer.parseInt(p);
}
#Override
public int compareTo(Item item) {
int c = price - item.price;
if (c == 0)
c = name.compareTo(item.name);
return c;
}
public static Item insert(Item root, Item item) {
if (root == null) {
item.count = 1;
return item;
}
int c = item.compareTo(root);
if (c < 0) {
root.left = insert(root.left, item);
} else {
root.right = insert(root.right, item);
}
++root.count;
return root;
}
public static Item itemAt(Item root, int ix) {
if (root == null) {
return null;
}
if (root.left != null) {
if (ix < root.left.count) {
return itemAt(root.left, ix);
}
ix -= root.left.count;
}
if (ix == 0) {
return root;
}
--ix;
if (root.right != null) {
if (ix < root.right.count) {
return itemAt(root.right, ix);
}
}
return null;
}
}
The average complexity is in O(log(n)), but as the tree is unbalanced, there are degenerate cases (when the items are entered sorted).
ERRATA: O(n*log(n))
I want to sort Token objects first based on their usedNumber bigger to smaller.
Then for the tokens have same usedNumber i want to sort them smaller to bigger based their priority number for example:
name priority usedNumber
a 1 3
b 2 4
c 3 0
d 4 3
e 5 3
f 6 4
Sorted version should be first bigger usedNumbers then smaller priorty:
b 2 4
f 6 4
a 1 3
d 4 3
e 5 3
c 3 0
Code below doesnt sort them correctly
public class Token {
int usedNumber;
int priority;
String name;
public Queue<Token> reversebubbleSort(Queue<Token> queue)
{
int n = queue.size();
int i;
int j;
Token temp;
boolean swapped;
for (i = 0; i < n - 1; i++)
{
swapped = false;
for (j = 0; j < n - i - 1; j++)
{
int namenumber1 = Integer.parseInt(queue.get(j).priority);
int namenumber2 = Integer.parseInt(queue.get(j+1).priority);
int number1 = queue.get(j).getUsedNumber();
int number2 = queue.get(j+1).getUsedNumber();
if (((number1^5)-namenumber1) < ((number2^5)-namenumber2))
{
// swap arr[j] and arr[j+1]
temp = queue.get(j);
queue.set(j, queue.get(j+1));
queue.set(j+1, temp);
swapped = true;
}
}
// IF no two elements were
// swapped by inner loop, then break
if (swapped == false)
break;
}
return queue;
}
Queue class in here is not from java.util. This is a class designed by me due the restrictions in my assigment. Queue class uses Arraylists to perform.
public class Queue<Token> {
private ArrayList<Token> queue;
public Queue() {
queue = new ArrayList<>();
}
public void add(Token addItem){
//In queues, adding in the back, first in first out.
queue.add(addItem);
}
public void removeFromFront(){
queue.remove(0);
}
public int size(){
return queue.size();
}
public Token get(int location){
return queue.get(location);
}
public void remove(int index){
queue.remove(index);
}
public void set(int location, Token setItem) {
queue.set(location, setItem);
}
}
}
Rather than wrapping ArrayList in your Queue, extend it: makes for simpler code
Don't use "Token" as a generic class name: it's confusing. Rather use the standard T
Which gives you code for Queue.java:
import java.util.ArrayList;
/*
* If it's only ever used for Token, it could also be
* public class Queue extends ArrayList<Token>
* and then you could override the sort method of ArrayList
* with the implementation shown in Token.sortSpecial below
*/
public class Queue<T> extends ArrayList<T> {
private static final long serialVersionUID = 1L;
public void removeFromFront() {
super.remove(0);
}
}
Method for sorting queues in class Token should be static: it's not linked to the state of an instance. I've renamed it sortSpecial. It also doesn't have to return, as the sorting is done in place on the Queue
Use List.sort with a custom Comparator to do the sorting
Fields should be private with getters and setters (which are not shown here)
Which gives you Token.java:
public class Token {
private String name;
private int priority;
private int usedNumber;
public Token(String name, int priority, int usedNumber) {
super();
this.usedNumber = usedNumber;
this.priority = priority;
this.name = name;
}
/* Getters and Setters go here */
/** Sort by usedNumber DESC / priority ASC */
public static void sortSpecial(Queue<Token> queue) {
queue.sort((x, y) -> {
int comp = -Integer.compare(x.usedNumber, y.usedNumber);
if (comp == 0)
comp = Integer.compare(x.priority, y.priority);
return comp;
});
}
#Override
public String toString() {
return getClass().getSimpleName() + "[" + name + " (p=" + priority + ", un=" + usedNumber + ")]";
}
}
Or if you want to play smart-ass, you could write the comparator as a one-liner (after defining your getters):
Comparator.comparingInt(Token::getUsedNumber).reversed().thenComparingInt(Token::getPriority)
Entry point for your program (Main.java):
public class Main {
public static void main(String[] args) {
Queue<Token> toks = new Queue<>();
toks.add(new Token("a", 1, 3));
toks.add(new Token("b", 2, 4));
toks.add(new Token("c", 3, 0));
toks.add(new Token("d", 4, 3));
toks.add(new Token("e", 5, 3));
toks.add(new Token("f", 6, 4));
System.out.println("Input:");
toks.stream().forEach(t -> System.out.println('\t' + t.toString()));
System.out.println();
Token.sortSpecial(toks);
System.out.println("Output:");
toks.stream().forEach(t -> System.out.println('\t' + t.toString()));
}
}
Console output:
Input:
Token[a (p=1, un=3)]
Token[b (p=2, un=4)]
Token[c (p=3, un=0)]
Token[d (p=4, un=3)]
Token[e (p=5, un=3)]
Token[f (p=6, un=4)]
Output:
Token[b (p=2, un=4)]
Token[f (p=6, un=4)]
Token[a (p=1, un=3)]
Token[d (p=4, un=3)]
Token[e (p=5, un=3)]
Token[c (p=3, un=0)]
I have an arraylist that looks like this:
public static ArrayList<ArrayList<String[]>> x = new ArrayList<>();
I store groups of 2 persons in a pair. For example:
[Person1, Person2]
[Person3, Person4]
The algorithm I use right now still makes duplicates, I've tried out hashmaps and iterating through them with for loop but they just give me back the original list.
This is the code:
package com.company;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
public class createGroups
{
public static ArrayList<ArrayList<String[]>> x = new ArrayList<>();
public static void main(String[] args){
//Define names
String[] names = {"Person1", "Person2", "Person3", "Person4"};
try
{
//Create combinations. In a try catch because of the saveFile method.
combination(names, 0, 2);
//Print all the pairs in the Arraylist x
printPairs();
} catch (IOException e)
{
e.printStackTrace();
}
}
static void combination(String[] data, int offset, int group_size) throws IOException
{
if(offset >= data.length)
{
//Create new Arraylist called foo
ArrayList<String[]> foo = new ArrayList<>();
//Create a pair of 2 (data.length = 4 / group_size = 2)
for(int i = 0; i < data.length / group_size; i++)
{
//Add the pair to foo.
foo.add(Arrays.copyOfRange(data, 2 * i, 2 * (i + 1)));
}
//Add foo to x
x.add(foo);
//saveFile(foo);
}
for(int i = offset; i < data.length; i++){
for(int j = i + 1; j < data.length; j++){
swap(data, offset, i);
swap(data, offset + 1, j);
combination(data, offset + group_size, group_size);
swap(data, offset + 1, j);
swap(data, offset, i);
}
}
}
public static void printPairs(){
//Print all pairs
for(ArrayList<String[]> q : x){
for(String[] s : q){
System.out.println(Arrays.toString(s));
}
System.out.println("\n");
}
}
private static void swap(String[] data, int a, int b){
//swap the data around.
String t = data[a];
data[a] = data[b];
data[b] = t;
}
}
The output right now is this:
Output
Every group of 4 names is a 'list' of pairs (Not really a list but that's what I call it)
And this is the desired output:
Desired output
But then you can see that the first and the last list of pairs are basically the same how do I change that in my combination method
The question:
How can I change my combination method so that it doesn't create duplicate groups.
And how can I make the list smaller (The desired output) when printing the created lists.
If I wasn't clear enough or if I didn't explain what I want very well, let me know. I'll try to make it clearer.
Create an object similar to this. It takes 4 strings (2 pairs). Puts the strings into array and sorts this array. That means any combination of strings you put in will be converted into one sorted combination, but the object internaly remembers which person is person1, person2, ...
private class TwoPairs {
private final String person1;
private final String person2;
private final String person3;
private final String person4;
private final String[] persons;
TwoPairs(String person1, String person2, String person3, String person4) {
this.person1 = person1;
this.person2 = person2;
this.person3 = person3;
this.person4 = person4;
persons = new String[4];
persons[0] = person1;
persons[1] = person2;
persons[2] = person3;
persons[3] = person4;
// if we sort array of persons it will convert
// any input combination into single (sorted) combination
Arrays.sort(persons); // sort on 4 objects should be fast
// hashCode and equals will be comparing this sorted array
// and ignore the actual order of inputs
}
// compute hashcode from sorted array
#Override
public int hashCode() {
return Arrays.hashCode(persons);
}
// objects with equal persons arrays are considered equal
#Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
TwoPairs other = (TwoPairs) obj;
if (!Arrays.equals(persons, other.persons)) return false;
return true;
}
// add methods which you might need
// getters for individual persons
// String getPerson1() { return person1; }
// or perhaps pairs of persons
// String[] getPair1() { return new String[] {person1, person2}; }
// add sensible toString method if you need it
}
Your ArrayList x will change like this
ArrayList<TwoPairs> x = new ArrayList<TwoPairs>();
before adding new TwoPairs object into x check if this list already contains this object.
if (!x.contains(twoPairsObject)) {
x.add(twoPairsObject);
}
My main class
int n, p;
String d;
manager m = new manager();
Scanner f = new Scanner(i.class.getResourceAsStream("product.txt"));
while (f.hasNextLine()) {
String[] s = f.nextLine().split(",");
n = Integer.parseInt(tokens[0]);
d = s[1];
p = Integer.parseInt(s[2]);
Item item = new Item(itemNo, description, price);
m.addItems(item);
if (s[3].contains("1")) {
m.addRep(1, item);
}
if (s[3].contains("2")) {
m.addRep(2, item);
}
if (s[3].contains("3")) {
m.addRep(3, item);
}
}
}
Example from my text File:
34,table,1200,12
14,sofa,2950,123
format of s[3] is e.g. "12" and "123" to represent that item is in repositories with ID's 1, 2 and 3
Error I am getting
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 1, Size: 0
at java.util.ArrayList.rangeCheckForAdd(ArrayList.java:643)
at java.util.ArrayList.add(ArrayList.java:455)
at dadsaassi.manager.addRep(manager.java:26)
Java Result: 1
My Item class
public int itemNum = 0;
public String des = "";
public int price = 0;
public Item(int i, String d, int p) {
itemNum = i;
des = d;
price = p;
}
My manager class
private ArrayList<Item> rep = new ArrayList<Item>();
private ArrayList<Item> list = new ArrayList<Item>(); //creates ArrayList
public void addItems(Item item) {
list.add(item);
}
public void addRep(int num, Item item) {
rep.add(num, item);
List is 0 index based. At manager.java, whenever you try to add at 1 index of rep ArrayList than rep.size()>0 is true.
m.addItemToRepository(1, item);
So, it throws IndexOutOfBoundsException. Look at docs of List.add(element, index) method.
IndexOutOfBoundsException - if the index is out of range (index < 0 ||
index > size())
The solution is, you should not mention index at rep List
m.addItemToRepository(item); //It will start from 0
or,
m.addItemToRepository(0, item);// Although index is here redundant.
Edit: If you need repository number, you can also use Map<Integer, Item>, where Integer is the repository number.
Map<Integer, Item> rep = new HashMap<Integer, Item>();
public void addItemToRepository(int num, Item item) {
rep.put(num, item);
}