Collections which increase number of occurrences instead of adding duplicate - java

Does exist any collection which stores only unique strings, but count how many times this string was added?
So every time, when I try add the same string/item again, number of items remain the same but numbers of occurrence of given item will increase?

You can use a HashMap and wrap some code around it:
public class CounterMap<K> {
private final Map<K, Integer> internalMap = new HashMap<K, Integer>();
public void increment(K key) {
initKeyIfNew(key);
Integer oldValue = internalMap.get(key);
Integer newValue = oldValue + 1;
internalMap.put(key, newValue);
}
public int getCount(K key) {
initKeyIfNew(key);
return internalMap.get(key);
}
private void initKeyIfNew(K key) {
if (internalMap.get(key) == null) {
internalMap.put(key, 0);
}
}
}
Then you can use it like this:
CounterMap<String> myCounterMap = new CounterMap<String>();
myCounterMap.increment("hello");
...

As far as I know, there is not such build in collections, but you can simply achieve that by using Map collection:
Map<String, Integer> map = new HashMap<>();
String sample = "foo";
if (map.containsKey(sample))
map.put(sample, map.get(sample) + 1);
You can also use solution from external library, for example Multiset from Google Guava:
Multiset<String> multiset = HashMultiset.create();
String test = "foo";
multiset.add(test);
multiset.add(test);
multiset.add(test);
System.out.println(multiset.count(test));
with output:
3
Hope it helps.

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class UniqueStringCount {
public static void main(String[] args) {
boolean takeUserInput = true;
HashMap<String, Integer> uniqueStringMap = new HashMap<>();
int counter = 0;
System.out.println("Welcome. To close the program type exit.");
System.out.println();
do {
Scanner scan = new Scanner(System.in);
System.out.println("Enter the unique string");
String userInput = scan.next();
if(userInput.equalsIgnoreCase("exit")) {
takeUserInput = false;
scan.close();
}
System.out.println();
if(!userInput.equalsIgnoreCase("exit")) {
if(uniqueStringMap.containsKey(userInput)) {
counter = uniqueStringMap.get(userInput);
uniqueStringMap.put(userInput, ++counter);
continue;
}
counter = 0;
uniqueStringMap.put(userInput, ++counter);
}
} while(takeUserInput);
if(!uniqueStringMap.isEmpty()) {
for(Map.Entry<String, Integer> entry : uniqueStringMap.entrySet()) {
System.out.println("String " + entry.getKey() + " was added " + entry.getValue() + " times.");
System.out.println();
}
System.out.println("Bye bye.");
}
}
}

With Java 8:
Map<String, Integer> map = new HashMap<>();
When adding a string, do:
map.merge(s, 1, Integer::sum);
What this does is add the string s and set the value to 1 if it wasn't there yet. If it was there already, then it takes the current value and the new value you're adding (1 again) and sums them, and puts that back into the map.

Related

adding to Maps in Java

Hi i am trying to add countries to a map see below code. I am able to input the countries but my out is not what i expected. The Set prints out 4 times where i want each country counting form 1-4 not each Set. can you help?
/**
* MY CODE SO FAR = pleae can you help
*/
import java.util.*;
class EuroGroupStages {
public static void main(String args[]) {
Map<Integer, Set<String>> groupA;
Map<Integer, Set<String>> groupB;
Map<Integer, Set<String>> groupC;
Map<Integer, Set<String>> groupD;
//public EuroGroupStages()
// {
groupA = new TreeMap<>();
groupB = new TreeMap<>();
groupC = new TreeMap<>();
groupD = new TreeMap<>();
// }
//public void addCountries()
// {
Scanner keyboard = new Scanner(System.in);
Set<String> country = new HashSet<>();
String aCountry;
for(int i = 1; i < 5; i++)
{
System.out.print("Please enter a country");
aCountry = keyboard.next();
country.add(aCountry);
groupA.put(i, country);
}
System.out.println(groupA);
keyboard.close();
// }
}
}
{1=[England, Scotland, Czech, Croatia], 2=[England, Scotland, Czech, Croatia], 3=[England, Scotland, Czech, Croatia], 4=[England, Scotland, Czech, Croatia]}
Instead of System.out.println(groupA);
try to write:
for(int i = 1; i < 5; i++)
{
System.out.println(groupA.get(i));
}
for getting the value of each key in groupA.
Edit:
Here are some examples for getting the combinations of key+value:
(https://www.techiedelight.com/iterate-map-using-keyset-java/)
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.stream.Stream;
public class Main
{
// Program to iterate map using `keySet()` in Java
public static void main(String[] args)
{
Map<Integer, String> map = new HashMap<>();
map.put(1, "One");
map.put(2, "Two");
map.put(3, "Three");
map.put(4, "Four");
// 1. Using an iterator
Iterator<Integer> itr = map.keySet().iterator();
while (itr.hasNext())
{
Integer key = itr.next();
String value = map.get(key);
System.out.println(key + "=" + value);
}
// 2. For-each loop
for (Integer key: map.keySet()) {
System.out.println(key + "=" + map.get(key));
}
// 3. Java 8 - Iterator.forEachRemaining()
map.keySet()
.iterator()
.forEachRemaining(key -> System.out.println(key + "=" + map.get(key)));
// 4. Java 8 - Stream.forEach()
map.keySet().stream()
.forEach(key -> System.out.println(key + "=" + map.get(key)));
// 5. Java 8 - Stream.of() + toArray() + forEach()
Stream.of(map.keySet().toArray())
.forEach(key -> System.out.println(key + "=" + map.get(key)));
}
}
Code is compileable in java-online compiler:
(https://www.tutorialspoint.com/compile_java_online.php)
One of these approaches is certainly applicable to your code.
You're putting each country in a set and then adding the whole set each time. What I think you want to do is to put the countries in individual sets and add those to the map (more information would be helpful). To do this, a new Set must be created in each iteration of the loop to hold the next country.
// first you can delare you maps like this.
Map<Integer, Set<String>> groupA= new TreeMap<>();
Scanner keyboard = new Scanner(System.in);
for(int i = 1; i < 5; i++) {
System.out.print("Please enter a country");
Set<String> country = new HashSet<>();
country.add(keyboard.next());
groupA.put(i, country);
}
groupA.entrySet().forEach(System.out::println);
Prints something like
1=[USA]
2=[Canada]
3=[Norway]
4=[England]
And do not close the Scanner when taking input from the keyboard.

sort by name and then add amount of each object with same name?

user can create as many instances of Thing as they please. a user inputs a string into the object with a number.
eg of created objects
Thing thing1 = new Thing("input1", 3);
Thing thing2 = new Thing("input2", 1);
Thing thing3 = new Thing("input2", 3000);
Thing thing4 = new Thing("input1", 4);
Thing thing5 = new Thing("input4", 200");
ArrayList<Thing> ThingList= new ArrayList<Thing>();
ThingList.add(thing1);
.....
.....
I need to have the the program search through an ArrayList of Things and output the inputed String with the combined total of all integers with the same inputed string
output example
name count
input1 7
input2 3001
input4 200
Im not sure how I can do this without doubling up on inputs with the same name. unless I compare to a name entered by me
what I have done so far (note it can only find and total what I have inputed for it to search.)
for( i= 0; i< ThingList.size(); i++){
inputedThingCheck = ThingList.get(i).getInputedName();
//testInput is the input I know for a fact is inside arraylist
if(inputedThingCheck.equals(testInput)){
thingTotal = ThingList.get(i).getCount() + thingTotal;
}
}
I want to know how to have the program search through each Thing object and add to a total the count of all things with the same name, while skipping the Thing that has already been done
You can try something like this with Collectors.groupingBy
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Thing {
private String key;
private int value;
public Thing(String key, int value) {
super();
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
#Override
public String toString() {
return "Thing [key=" + key + ", value=" + value + "]";
}
public static void main(String[] args) {
List<Thing> source = Arrays.asList(
new Thing("input1", 3),
new Thing("input2", 1),
new Thing("input2", 3000),
new Thing("input1", 4),
new Thing("input4", 200));
List<Thing> target = source.stream().collect(Collectors.groupingBy(thing -> thing.key)).entrySet().stream()
.map(e -> e.getValue().stream().reduce((f1, f2) -> new Thing(f1.key, f1.value + f2.value)))
.map(f -> f.get()).collect(Collectors.toList());
System.out.println(target);
}
}
Thank you!
you can also implement the groupby function for example java 8
Map<String, Integer> sum = list.stream().collect(
Collectors.groupingBy(Thing::getkey, Collectors.summingInt(Thing::getValue)));
Instead of using ArrayList to contain the thing object, I guess it would be easier if we store it as a key, value pair. The key can be the name of the thing, and the value can an array containing the count of that particular key.
ArrayList<Thing> foo = new ArrayList<Thing>();
foo.add(thing1);
foo.add(thing2);
foo.add(thing3);
foo.add(thing4);
foo.add(thing5);
Map<String, ArrayList<Integer>> ThingList = new HashMap<String, ArrayList<Integer>>();
for (Thing x : foo){
if (ThingList.containsKey(x.getName())){
ArrayList value = ThingList.get(x.getName());
value.add(x.getValue());
}
else{
container = new ArrayList<Integer>();
container.add(x.getValue());
ThingList.put(x.getName(), container);
}
}
// Debug to check the key, value pair of ThingList
// System.out.println(Arrays.asList(ThingList));
// Loop through ThingList and get the key + sum of its related values
for (Map.Entry<String, ArrayList<Integer>> entry : ThingList.entrySet()) {
String key = entry.getKey();
ArrayList value = entry.getValue();
int valueSum = 0;
for (int i=0 ; i < value.size() ; i++){
valueSum += (Integer)value.get(i);
}
// Print the output
System.out.println(key + " " + String.valueOf(valueSum));
}
}

Java Collections - Print interstates sorted by population, city and state

I am working on a problem I came across in an interview.
Input contains Population|City|State|Interstates list
Output needs to be sorted in descending order by population first, then alphabetically by city and state, and then the interstates need to be sorted in ascending order too.
Sample input:
27|Chicago|Illinois|I-94;I-90;I-88;I-57;I-55
83|New York|New York|I-78;I-95;I-87;I-80
15|Phoenix|Arizona|I-10;I-17;I-8
15|Philadelphia|Pennsylvania|I-95;I-76
Sample output:
83
New York, New York
Interstates: I-78, I-80, I-87, I-95
27
Chicago, Illinois
Interstates: I-55, I-57, I-88, I-90, I-94
15
Philadelphia, Pennsylvania
Interstates: I-76, I-95
Phoenix, Arizona
Interstates: I-8, I-10, I-17
Here's my approach so far. I am currently stuck in the if block where I've added a comment. I am not sure if I am going in the right direction. I am looking for a hint to take the right approach here.
Scanner sc = new Scanner(System.in);
String line;
List<String> al = new ArrayList<>();
//Outer map sorts reverse by population, inner map1 sorts by city, inner
map2 sorts by state
Map<Integer, Map<String, Map<String, String>>> outerMap = new TreeMap<>
(Collections.reverseOrder());
Map<String, Map<String, String>> innerMap1 = new TreeMap<>();
Map<String, String> innerMap2 = new TreeMap<>();
while(sc.hasNextLine() && (line = sc.nextLine()).length()!=0) {
//Ignore if input contains this character
if(line.contains("#")) {
line = sc.nextLine();
}
al.add(line);
}
for(int i = 0; i < al.size(); i++) {
int outerMapKey = Integer.parseInt(al.get(i).split("\\|")[0]);
String innerMap1Key = al.get(i).split("\\|")[1];
String innerMap2Key = al.get(i).split("\\|")[2];
String value = al.get(i);
outerMap.get(outerMapKey);
if(outerMap.containsKey(outerMapKey)) {
innerMap1 = outerMap.get(outerMapKey);
/* Logic to put values in inner maps
This is going to get very convoluted, not sure if I have the
right approach
*/
}
else {
innerMap1 = new TreeMap<>();
innerMap2 = new TreeMap<>();
innerMap2.put(innerMap2Key, value);
innerMap1.put(innerMap1Key, innerMap2);
outerMap.put(outerMapKey, innerMap1);
}
}
Thank you for all your help so far. I am posting my code (working now) based on feedback here. Please take a look and suggest how it can be improved.
public static void main(String[] args) {
Map<String, List<PopulationByCityState>> map = readAndProcessInput();
printSortedOutput(map);
}
private static Map<String, List<PopulationByCityState>> readAndProcessInput() {
Map<String, List<PopulationByCityState>> map = readInput();
sortByPopulationCityAndState(map);
return map;
}
private static Map<String, List<PopulationByCityState>> readInput() {
System.out.println("Enter input:");
Scanner sc = new Scanner(System.in);
String line;
Map<String, List<PopulationByCityState>> map = new TreeMap<>(Collections.reverseOrder());
while (sc.hasNextLine() && (line = sc.nextLine()).length() != 0) {
if (line.contains("#")) {
line = sc.nextLine();
}
populateMap(line, map);
}
return map;
}
private static void populateMap(String line, Map<String, List<PopulationByCityState>> map) {
String[] s = line.split("\\|");
String[] is = s[3].split(";");
String key = s[0];
PopulationByCityState p = new PopulationByCityState();
p.setPopulation(Long.parseLong(s[0]));
p.setCity(s[1]);
p.setState(s[2]);
List<String> interstates = new ArrayList<>();
for (String aString : is) {
interstates.add(aString);
}
sortInterstates(interstates);
p.setInterstates(interstates);
if (map.containsKey(key)) {
map.get(key).add(p);
} else {
List<PopulationByCityState> al = new ArrayList<>();
al.add(p);
map.put(key, al);
}
}
private static void sortInterstates(List<String> interstates) {
Collections.sort(interstates, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
int n1 = Integer.parseInt(o1.split("-")[1]);
int n2 = Integer.parseInt(o2.split("-")[1]);
return n1 - n2;
}
});
}
private static void sortByPopulationCityAndState(Map<String, List<PopulationByCityState>> map) {
for (Map.Entry entry : map.entrySet()) {
List<PopulationByCityState> list = (List<PopulationByCityState>) entry.getValue();
Collections.sort(list, new Comparator<PopulationByCityState>() {
#Override
public int compare(PopulationByCityState o1, PopulationByCityState o2) {
int c;
c = (int) (o2.getPopulation() - o1.getPopulation());
if (c == 0) {
c = o1.getCity().compareTo(o2.getCity());
}
if (c == 0) {
c = o1.getState().compareTo(o2.getState());
}
return c;
}
});
}
}
private static void printSortedOutput(Map<String, List<PopulationByCityState>> map) {
for (Map.Entry<String, List<PopulationByCityState>> entry : map.entrySet()) {
System.out.println(entry.getKey());
System.out.println();
List<PopulationByCityState> list = entry.getValue();
for (PopulationByCityState p : list) {
System.out.println(p.getCity() + ", " + p.getState());
List<String> interstates = p.getInterstates();
System.out.print("Interstates: ");
int s = 0;
for (String is : interstates) {
s++;
System.out.print(is);
if (s != interstates.size()) {
System.out.print(", ");
}
}
System.out.println();
System.out.println();
}
}
}
Your approach relies on over complicated and not meaningful structure and also uses a Comparator that will only sort the first level of the map :
Map<Integer, Map<String, Map<String, String>>> outerMap = new TreeMap<>
(Collections.reverseOrder());
A finer approach could rely on using a class that represents each individual information that you need to represent a population for a state : PopulationForState
Here is a very simple representation of it (that is of course improvable but that should help you to understand the logic) :
public class PopulationForState{
private long population;
private String city;
private String state;
private List<String> interstates;
...
// getters
}
Add instances of them in a List and use a comparator that sorted them in descending order by population first, then alphabetically by city and state.
The interstates field may be sorted independently or directly during the sort of outer elements.
You could provide a sort method in PopulationForState, for example sortInnerStates() that sorts them in ascending order.
Personally, I would make it independently to keep the processing less coupled between.
So you could write something like :
List<PopulationForState> populationForStates = new ArrayList<>();
populationForStates.add(new PopulationForState(...));
populationForStates.add(new PopulationForState(...));
Collection.sort(populationForStates, Comparator.comparing(PopulationForState::population).reversed()
.thenComparing(PopulationForState::getCity)
.thenComparing(PopulationForState::getState);
populationForStates.stream()
.forEach(PopulationForState::sortInnerStates);
If you have a structure such the one posted in above post:
public class PopulationForState{
public long population;
public String city;
public String state;
public List<String> interstates;
//Do encapsulate
}
You can sort it with one comparator:
Collections.sort(populatisForStates, new Comparator<PopulationForState>(){
public int compare(PopulationForState first, PopulationForState scnd) {
int compare = first.population - scnd.population;
if(compare != 0) return compare;
compare = first.city.compareTo(scnd.city);
if(compare != 0) return compare;
return first.state.compareTo(scnd.state);
}
});
Sorting Interstates is similar and you just need to use Collections.sort(interstates) on each instance.

How to get input from user for Hashmap using Scanner

How to get input from user for Hashmap using scanner and print the respective hashmap?
import java.util.HashMap;
import java.util.Scanner;
public class Map {
public static void main(String[] args) {
HashMap<Integer, Integer> hmap = new HashMap<>();
Scanner in = new Scanner(System.in);
for (int i = 0; i < 3; i++) {
Integer a = in.nextInt();
Integer b = in.nextInt();
hmap.put(a, b);
System.out.println(hmap.put(a, b));
}
}
}
I am not getting the desired output. I want to print what is inserted in hmap.
Change your System.out.println statement to,
System.out.println(hmap.get(a));
This is another way to put data into a HashMap at runtime:
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
class MapDemo {
public static void main(String[] args) {
HashMap<Integer, String> hmap = new HashMap<>();
Scanner in = new Scanner(System.in);
for (int i = 0; i < 3; i++) {
Integer a = in.nextInt();
String b = in.next();
hmap.put(a, b);
}
for (Map.Entry<Integer, String> m : hmap.entrySet()) {
System.out.println(m.getKey() + " " + m.getValue());
}
}
}
Javadoc for the HashMap util can be found here.
To add a key/value pair to a HashMap you use hashmap.put(x, y).
Using hashmap.get(x) at a later time will return y.
Edit: It looks like from other comments you are trying to have it print out both the key and the value. In the case that you are trying to print out all keys and values something like this may work.
hashMap.forEach((e, k) -> {
System.out.println("E: " + e + " K: " + k);
})
If this is not your intended purpose I would strongly recommend reading over the method summary section of the javadocs.
What do you expect this to do? It is wrong, why would you print hmap.put(a,b)
System.out.println(hmap.put(a,b));
Just take it out of the for loop and print it separately
for (Map.Entry<Integer, Integer> pair: hmap.entrySet()) {
System.out.println(pair.getKey() + "->" + pair.getValue());
}
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
class Call {
public static void main(String[] as) {
getData();
}
public static void getData() {
Map<Integer, String> hashmap = new HashMap<>();
Scanner sc = new Scanner(System.in);
System.out.print("Shashank Pathak\nEnter number of character: ");
int n = sc.nextInt();
int[] a = new int[n];
for (int i = 0; i < a.length; i++) {
Integer b = sc.nextInt();
String c = sc.nextLine();
hashmap.put(b, c);
}
for (Map.Entry<Integer, String> mp : hashmap.entrySet()) {
System.out.println("\n" + mp.getKey() + " " + mp.getValue());
}
}
}
I find this, And it is exactly the same as I want.
System.out.println("How many producs you want");
int listOfItem = sc.nextInt();
System.out.println("Type the product name and quantity you want to purchace and get the bill");
HashMap<Integer, String> products = new HashMap<>();
while(listOfItem-- >0){
products.put(sc.nextInt(),sc.nextLine());
}
System.out.println(products);
Output of above program
import java.util.*;
class hash1 {
void dic(){
HashMap<Integer,Integer> hmap = new HashMap<Integer,Integer>();
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
int b = sc.nextInt();
hmap.put(a,b);
System.out.println(hmap);
}
}
public class answer {
public static void main(String[] args) {
hash1 obj = new hash1();
for(int z = 0;z < 3;z++){
obj.dic();
}
}
}

Need a Fresh pair of Eyes to Work Out the Logic Behind Comparing Values in a Map of Maps

Problem
Data is in the format:
Map<String, Map<String, Integer>>
Which looks something like this:
{"MilkyWay": {"FirstStar" : 3, "SecondStar" : 9 .... }, "Andromeda": {"FirstStar" : 10, "SecondStar" : 9 .... } }
I want to compare the Star values in a quick loop, so I'd like to compare the integer value of FirstStar in MilkyWay and Andromeda and have it return true or falseif the values are the same or not. Since this Map of Maps is huge.
My Attempt
I'd like to do it something like:
//GalaxyMap<String, <Map<String, Integer>>
for (Map<String, Integer> _starMap : GalaxyMap.values())
{
for (String _starKey : _starMap.keySet()){
//Can't quite think of the correct logic... and I'm tired...
}
}
I'd like to keep it as short as possible... I've been staring at this for a while and I'm going in circles with it.
EDIT
Outer keys differ, Inner keys are the same
Also since this is a response from a server, I don't know the size it's going to be
Why does this need to be a map. If you're always using "FirstStar", "SecondStar" etc, as your keys, then why not make it a list instead..
Map<String, List<Integer>>
Then you can do something like:
public boolean compareGalaxyStar(String galaxyName, String otherGalaxyName, int star) {
List<Integer> galaxyStars = galaxyMap.get(galaxyName);
List<Integer> otherGalaxyStars = galaxyMap.get(otherGalaxyName);
return galaxyStars.get(star) == otherGalaxyStars.get(star);
}
NOTE: You need to do some validation to make sure the input is correct.
To implement this for all stars, it is not much different.
if(galaxyStars.size() == otherGalaxyStars.size()) {
for(int x = 0; x < galaxyStars.size(); x++) {
// Perform your comparisons.
if(galaxyStars.get(x) != otherGalaxyStars.get(x)) {
// Uh oh, unequal.
return false;
}
}
}
If the structure of the inner maps also could differ, you should do something like that:
static boolean allStarValuesEqual(Map<String, Map<String, Integer>> galaxies) {
Map<String, Integer> refStars = null;
for (Map<String, Integer> galaxy : galaxies.values()) {
if (refStars == null) {
refStars = galaxy;
} else {
for (Entry<String, Integer> currentStar : galaxy.entrySet()) {
if (!currentStar.getValue().equals(refStars.get(currentStar.getKey()))) {
return false;
}
}
}
}
return true;
}
Please check below program along with output:
package com.test;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class CompareMapValues {
private final static String FS = "FirstStar";
private final static String SS = "SecondStar";
private final static String MW = "MilkyWay";
private final static String A = "Andromeda";
public static void main(String[] args) {
Map> map = new HashMap>();
Map innerMap1 = new HashMap();
innerMap1.put(FS, 3);
innerMap1.put(SS, 9);
Map innerMap2 = new HashMap();
innerMap2.put(FS, 10);
innerMap2.put(SS, 9);
map.put(MW, innerMap1);
map.put(A, innerMap2);
Set set = map.keySet();
for(String s: set) {
Map outerMap = map.get(s);
Set set2 = map.keySet();
for(String s2: set2) {
Map innerMap = map.get(s2);
if(!s2.equals(s)) {
Set set3 = outerMap.keySet();
for(String s3: set3) {
int i1 = outerMap.get(s3);
Set set4 = innerMap.keySet();
for(String s4: set4) {
int i2 = innerMap.get(s3);
if(s3.equals(s4) && i1==i2) {
System.out.println("For parent " + s + " for " + s3 + " value is " + i1);
}
}
}
}
}
}
}
}
//Output:
//For parent Andromeda for SecondStar value is 9
//For parent MilkyWay for SecondStar value is 9
Hope this helps.

Categories

Resources