Subtracting values in 2 different list in android - java

I have a integer array of years and its corresponding values it looks like the below code
int[] earningYear = {2012,2013,2014};
int[] earningAmount = {100,150,120};
int[] expenseYear = {2012,2014};
int[] expenseAmount = {50,30};
i want to subtract expenseAmount from earningsAmount corresponding to year and the output list should look like this
int[] savingsYear = {2012,2013,2014};
int[] savingsamount = {50,150,90};
please help me in doing this. Thanks in advance

Answers given by #umair.ali and #Casper are good, converting your arrays to Maps is the way to go.
I would suggest using TreeMap (or other implementation of SortMap interface). TreeMap sorts its keys in ascending order by default. That way, if you really want to have plain array of savings as result, you won't have to do any awkward map sorting after processing.
Here's complete example:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
public class SavingsApp {
public Map<Integer, Integer> arraysToMap(int[] years, int[] money) {
Map<Integer, Integer> newMap = new HashMap<Integer, Integer>();
if (years == null || money == null || years.length != money.length) {
throw new IllegalArgumentException();
}
for (int i=0; i< years.length; i++ ) {
newMap.put(years[i], money[i]);
}
return newMap;
}
public Map<Integer, Integer> calculateSavings(Map<Integer, Integer> earningsMap, Map<Integer, Integer>expensesMap) {
Map<Integer, Integer> savingsMap = new TreeMap<Integer, Integer>();
savingsMap.putAll(earningsMap);
for (Entry<Integer, Integer> expensePerYear : expensesMap.entrySet()) {
Integer year = expensePerYear.getKey();
Integer expense = expensePerYear.getValue();
Integer earning = savingsMap.get(year);
if (earning == null) {
earning = 0;
}
savingsMap.put(year, earning-expense);
}
return savingsMap;
}
public static void main(String[] args) {
int[] earningYear = {2012,2013,2014};
int[] earningAmount = {100,150,120};
int[] expenseYear = {2012,2014};
int[] expenseAmount = {50,30};
SavingsApp app = new SavingsApp();
// convert arrays to maps
Map<Integer, Integer> earningsMap = app.arraysToMap(earningYear, earningAmount);
Map<Integer, Integer> expensesMap = app.arraysToMap(expenseYear, expenseAmount);
// compute savings per year
Map<Integer, Integer> savingsMap = app.calculateSavings(earningsMap, expensesMap);
// convert result map to array
List<Integer> savingsList = new ArrayList<Integer>(savingsMap.values());
Integer[] savingsArray = new Integer[savingsList.size()];
savingsList.toArray(savingsArray);
}
}
One thing to notice is that savingsArray will be of Integer[] type instead of int[].

If earningYear always contains all years and both earningYear and expenseYear are sorted, then this would be a possible solution
int[] earningYear = {2012,2013,2014};
int[] earningAmount = {100,150,120};
int[] expenseYear = {2012,2014};
int[] expenseAmount = {50,30};
int[] savingsYear = new int[earningYear.length()];
int[] savingsAmount = new int[earningYear.length()];
int expenseYearIndex = 0;
for(int i = 0; i < earningYear.length(); i++) {
savingsYear[i] = earningYear[i];
savingsAmount[i] = earningsAmount[i];
if(expenseYear.length() > 0 && expenseYear[expenseYearIndex] == earningYear[i]) {
savingsAmount[i] -= expenseYear[expenseYearIndex];
expenseYearIndex++;
}
}
This should do it.
However a better solution would be something with a List, already suggested, and some objects holding the year and the amount for the year.

Related

Push An ArrayList of Strings Into HashMap

I am trying to split each element of an ArrayList into a char and double and push the results into a HashMap. So far, my code is this:
public static int TotalAmount(ArrayList<String> x) {
HashMap<Character,Double> hm = new HashMap<Character,Double>();
for(int i = 0; i < x.size(); i++) {
String[] s = x.get(i).split("(?<=\\d)(?=[a-zA-Z])");
hm.put(s[1].charAt(0), Double.parseDouble(s[0]));;
}
I do this with the ArrayList holding:
234K
1.3M
2.1M
211H
11K
But when I iterate through the HashMap, I get:
H, 211
K, 11
M, 2.1
I cannot seem to find where my logic went wrong. I might be able to accredit this to my intro to HashMaps. How do I ensure that I convert the ArrayList of Strings into a HashMap correctly?
To clear things up, I'm trying to completely move the ArrayList into a HashMap, without overwriting when the same key is found.
You can try this:
public static HashMap<Character, List<Double>> TotalAmount(ArrayList<String> initialList) {
HashMap<Character, List<Double>> resultMap = new HashMap<>();
for (String line : initialList) {
Double size = Double.parseDouble(line.substring(0, line.length() - 1));
Character sizeChar = line.charAt(line.length() - 1);
if (resultMap.containsKey(sizeChar)) {
resultMap.get(sizeChar).add(size);
} else {
resultMap.put(sizeChar, Collections.singletonList(size));
}
}
return resultMap;
}
Try this! I tested and it works fine! As QBrute mentioned, HashMap's put() overrides any value that is processed with the same key earlier.
I created method and the test(in main) using HashMap>
.
import java.util.*;
public class Question {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("234K");
list.add("1.3M");
list.add("2.1M");
list.add("221H");
list.add("11K");
HashMap<Character, ArrayList<Double>> result = TotalAmount(list);
System.out.println("K: " + result.get('K'));
System.out.println("M: " + result.get('M'));
System.out.println("H: " + result.get('H'));
}
public static HashMap<Character, ArrayList<Double>> TotalAmount(
ArrayList<String> x) {
HashMap<Character, ArrayList<Double>> map = new HashMap<>();
for (String line : x) {
Double num = Double.parseDouble(line.substring(0,
line.length() - 1));
Character c = line.charAt(line.length() - 1);
if (map.containsKey(c)) {
map.get(c).add(num);
} else {
ArrayList<Double> newList = new ArrayList<>();
newList.add(num);
map.put(c, newList);
}
}
return map;
}
}

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.

Java - Sort one array based on values of another array?

I have an array of Strings that are instances of a class from external code that I would rather not change.
I also have an array of ints that was generated by calling a function on each object. So I have
A: [string1, string2, string3]
And
B: [40, 32, 34]
How do I easily sort A such that it is sorted in by the values of B. I have boost available. I want to sort A such that it is in the order:
[string2, string3, string1]
In javascript you could do this like:
B.sort(function(a,b){return A[B.indexOf(a)] < A[B.indexOf(b)];});
In java 8, you can do this
with a lambda:
String[] strings = new String[]{"string1", "string2", "string3"};
final int[] ints = new int[]{40, 32, 34};
final List<String> stringListCopy = Arrays.asList(strings);
ArrayList<String> sortedList = new ArrayList(stringListCopy);
Collections.sort(sortedList, (left, right) -> ints[stringListCopy.indexOf(left)] - ints[stringListCopy.indexOf(right)]);
Or better, with Comparator:
String[] strings = new String[]{"string1", "string2", "string3"};
final int[] ints = new int[]{40, 32, 34};
final List<String> stringListCopy = Arrays.asList(strings);
ArrayList<String> sortedList = new ArrayList(stringListCopy);
Collections.sort(sortedList, Comparator.comparing(s -> ints[stringListCopy.indexOf(s)]));
Short answer: I suggest that a separate class is created that holds the information about both the actual String and the boosting (the int). If you assume the following:
public class BoostString {
int boost;
String str;
public BoostString(int boost, String str) {
this.boost = boost;
this.str = str;
}
}
Then, you can sort your array by using a Comparator and it works especially nice with the Java 8 Streaming API.
String[] strings = {"string1", "string2", "string3"};
int[] boosts = {40, 32, 34};
final String[] sorted = IntStream.range(0, boosts.length)
.mapToObj(i -> new BoostString(boosts[i], strings[i])) // Create the instance
.sorted(Comparator.comparingInt(b -> b.boost)) // Sort using a Comparator
.map(b -> b.str) // Map it back to a string
.toArray(String[]::new); // And return an array
The Comparator in the example above is created using the Comparator.comparingInt method which is a convenient way of creating a Comparator for ints using Java 8.
Explanation: Typically when comparing objects in Java you use one of the built-in sorting functions such as Collections.sort where you provide your own Comparator. The Comparator interface is straightforward and looks like this:
public interface Comparator<T> {
int compare(T o1, T o2);
// Other default methods for Java 8
}
The return value is of type int and is described like this in the JavaDoc:
return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
This works out-of-the-box when you are sorting Strings or int (or actually Integers) since they are Comparable – they sort of have a built-in natural sorting and for Strings this is in alphabetical order and for Integers this is sorted in ascending number order (see the JavaDoc for Comparable).
On a side note, there are other "pair" or "tuple" implementations available if you are using 3rd party libraries. You do not have to create your own "pair" of a String and int. One example is the Pair class from Apache Commons.
As #wassgren said, you can use streams, but you don't have to create a class, you can just use indexes:
String[] strings = {"string1", "string2", "string3"};
int[] boosts = {40, 32, 34};
String[] sorted = IntStream.range(0, boosts.length).boxed()
.sorted(Comparator.comparingInt(i -> boosts[i]))
.map(i -> strings[i])
.toArray(String[]::new);
First you create a stream of indexes, then you sort them acording to boosts and then you get the string in that index.
You can do something similar to your JS example in old style Java (but I would recommend joining your data together in an object as #wassgren suggests):
import java.util.*;
public class WeightSort {
public static void main(String[] args) {
String[] strings = new String[]{"string1", "string2", "string3"};
final int[] weights = new int[]{40, 32, 34};
final List<String> stringList = Arrays.asList(strings);
List<String> sortedCopy = new ArrayList<String>(stringList);
Collections.sort(sortedCopy, new Comparator<String>(){
public int compare(String left, String right) {
return weights[stringList.indexOf(left)] - weights[stringList.indexOf(right)];
}
});
System.out.println(sortedCopy);
}
}
I solved this problem by using Comparator interface.
import java.util.Comparator;
import java.util.Collections;
import java.util.List;
import java.util.Arrays;
public class ComparatorDemo {
public static void main(String[] args) {
List<Area> metaData = Arrays.asList(
new Area("Joe", 24),
new Area("Pete", 18),
new Area("Chris", 21),
new Area("Rose",21)
);
Collections.sort(metaData, new ResultComparator());
for(int i =0 ;metaData.size()>i;i++)
System.out.println(metaData.get(i).output);
}
}
class ResultComparator implements Comparator<Area> {
#Override
public int compare(Area a, Area b) {
return a.result < b.result ? -1 : a.result == b.result ? 0 : 1;
}
}
class Area{
String output;
int result;
Area(String n, int a) {
output = n;
result = a;
}
}
If you're constructing array B only to be used for this sorting, you can defer calculating it's values within A's compareTo(). In other words, calculate weights of strings only in comparisons during sorting.
package com.appkart.array;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
public class SortExample {
Map<String, Integer> map = new HashMap<String, Integer>();
Map<String, Integer> treemap = new TreeMap<String, Integer>(
new MyComparator(map));
public void addValueInMapAndSort() {
map.put("string1", 40);
map.put("string2", 32);
map.put("string3", 34);
System.out.println(map);
treemap.putAll(map);
System.out.println(treemap);
}
class MyComparator implements Comparator<String> {
Map<String, Integer> map;
public MyComparator(Map<String, Integer> map) {
this.map = map;
}
#Override
public int compare(String o1, String o2) {
if (map.get(o1) >= map.get(o2)) {
return 1;
} else {
return -1;
}
}
}
public static void main(String[] args) {
SortExample example = new SortExample();
example.addValueInMapAndSort();
}
}
Use Comparator for sorting according to value.
I had a similar problem, and solved it by coding a sorting algorithm which sorted an array of measures, and made identical swaps in the array of objects. Here is the code, with tests, best wishes and no promises:
package other;
import java.util.Arrays;
import java.util.Random;
/**
* Sorts an array of objects (<code>bags</code>) by a separate array of doubles (<code>measures</code>).
* It sorts into ascending order.
* <p>
* The <code>results</code> array is always a new array.
* <p>
* The algorithm used:<ul>
* <li> Is (I believe) a merge-sort, which would mean it is stable. (I haven't tested this.)
* <li> Efficiently exploits already ordered subsequences.
* <li> Requires the allocation of eight arrays: four of the baggage type, four of doubles, each the length of the original data.
* </ul>
* <p>
* A <code>NaN</code> in the <code>measures</code> - I haven't thought about that, and don't want to.
* <p>
* There is test code at the end of the class.
*/
public class SortBaggageByDouble {
public final Object [] results ;
protected final int length ;
public SortBaggageByDouble(Object[] bags, double[] measures) {
this.length = bags.length;
if (bags.length!=measures.length) throw new IllegalArgumentException("Mismatched lengths: payload array "+bags.length+", measures array "+measures.length);
this.results = new Object[length];
Object [] bagsA = new Object[length] ;
Object [] bagsB = new Object[length] ;
Object [] bagsC = new Object[length] ;
Object [] bagsD = new Object[length] ;
double [] measuresA = new double[length] ;
double [] measuresB = new double[length] ;
double [] measuresC = new double[length] ;
double [] measuresD = new double[length] ;
System.arraycopy(bags, 0, bagsA, 0, length);
System.arraycopy(measures, 0, measuresA, 0, length);
munge(length, 0, bagsA, bagsB, bagsC, bagsD, measuresA, measuresB, measuresC, measuresD);
}
private void munge(int inLengthA, int inLengthB, Object[] inBagsA, Object[] inBagsB, Object[] outBagsC, Object[] outBagsD, double[] inMeasuresA, double[] inMeasuresB, double[] outMeasuresC, double[] outMeasuresD) {
int outLengthC = 0 ;
int outLengthD = 0 ;
int cursorA = 0 ;
int cursorB = 0 ;
boolean toC = true ;
while(outLengthC+outLengthD<length) {
boolean fromA ;
if (cursorA>=inLengthA) {
fromA = false ;
} else if (cursorB>=inLengthB) {
fromA = true ;
} else {
fromA = inMeasuresA[cursorA] <= inMeasuresB[cursorB] ;
}
double tmpMeasure = fromA ? inMeasuresA[cursorA] : inMeasuresB[cursorB] ;
Object tmpBag = fromA ? inBagsA[cursorA] : inBagsB[cursorB] ;
if (fromA) cursorA ++ ; else cursorB ++ ;
if (toC) {
if (outLengthC==0 || (outMeasuresC[outLengthC-1]<=tmpMeasure)) {
outMeasuresC[outLengthC] = tmpMeasure ;
outBagsC[outLengthC] = tmpBag ;
outLengthC ++ ;
} else {
toC = false ;
outMeasuresD[outLengthD] = tmpMeasure ;
outBagsD[outLengthD] = tmpBag ;
outLengthD ++ ;
}
} else {
if (outLengthD==0 || (outMeasuresD[outLengthD-1]<=tmpMeasure)) {
outMeasuresD[outLengthD] = tmpMeasure ;
outBagsD[outLengthD] = tmpBag ;
outLengthD ++ ;
} else {
toC = true ;
outMeasuresC[outLengthC] = tmpMeasure ;
outBagsC[outLengthC] = tmpBag ;
outLengthC ++ ;
}
}
}
if (outLengthC==length) {
System.arraycopy(outBagsC, 0, results, 0, length);
} else {
munge(outLengthC, outLengthD, outBagsC, outBagsD, inBagsA, inBagsB, outMeasuresC, outMeasuresD, inMeasuresA, inMeasuresB);
}
}
/**
* Subclass to sort strings, with a result object <code>sortedStrings</code> which is of a useful type.
*/
public static class Strings extends SortBaggageByDouble {
public final String [] sortedStrings ;
public Strings(String[] in, double[] measures) {
super(in, measures);
this.sortedStrings = new String[results.length];
for (int i=0 ; i<results.length ; i++) sortedStrings[i] = (String) results[i] ;
}
}
/**
* Tests sorting - assumes there are no duplicates among the measures.
*/
private static class NoDuplicatesTest {
private NoDuplicatesTest(String[] shuffledStrings, double[] shuffledMeasures, String[] expectedStrings) {
SortBaggageByDouble.Strings sorter = new SortBaggageByDouble.Strings(shuffledStrings, shuffledMeasures);
if (!Arrays.equals(expectedStrings, sorter.sortedStrings)) throw new RuntimeException("Test failed");
}
}
private static class MultiseedNoDuplicatesTest {
private MultiseedNoDuplicatesTest(String[] orderedStrings, double[] orderedMeasures, int[] seeds) {
int length = orderedStrings.length;
for (int seed : seeds) {
Random random = new Random(seed);
int [] shuffleIndices = new int[length] ;
for (int i=0 ; i<length ; i++) shuffleIndices[i] = i ;
for (int i=1 ; i<length ; i++) {
int j = random.nextInt(i+1); // 'j' is in the range 0..i, bounds inclusive.
int tmp = shuffleIndices[i];
shuffleIndices[i] = shuffleIndices[j] ;
shuffleIndices[j] = tmp ;
}
String[] shuffledStrings = new String[length];
double[] shuffledMeasures = new double[length];
for (int i=0 ; i<length ; i++) {
shuffledStrings[shuffleIndices[i]] = orderedStrings[i] ;
shuffledMeasures[shuffleIndices[i]] = orderedMeasures[i] ;
}
if (false && 0<length && length<8) {
System.out.println("shuffleIndices is "+ stringfor(shuffleIndices));
System.out.println("shuffledStrings is "+ stringfor(shuffledStrings));
System.out.println("shuffledMeasures is "+ stringfor(shuffledMeasures));
}
new NoDuplicatesTest(shuffledStrings, shuffledMeasures, orderedStrings);
}
}
}
private static class MultilengthMultiseedNoDuplicatesTest {
MultilengthMultiseedNoDuplicatesTest(int[] lengths, int[] seeds) {
for (int i=0 ; i<lengths.length ; i++) {
int length = lengths[i] ;
String[] orderedStrings = new String[length] ;
double[] orderedMeasures = new double[length] ;
for (int j=0 ; j<length ; j++) {
orderedStrings[j] = "_"+j+"_" ;
orderedMeasures[j] = j ;
}
if (false && 0<length && length<8) {
System.out.println("orderedStrings is "+ stringfor(orderedStrings));
System.out.println("orderedMeasures is "+ stringfor(orderedMeasures));
}
new MultiseedNoDuplicatesTest(orderedStrings, orderedMeasures, seeds);
}
}
}
public static class ClassTest {
ClassTest() {
new MultilengthMultiseedNoDuplicatesTest(new int[]{0}, new int[]{8543, 45125});
new MultilengthMultiseedNoDuplicatesTest(new int[]{1}, new int[]{8543, 45125});
new MultilengthMultiseedNoDuplicatesTest(new int[]{2}, new int[]{8543, 45125, 4545, 785413});
new MultilengthMultiseedNoDuplicatesTest(new int[]{3, 4, 5, 6, 7, 8, 9, 10}, new int[]{8543, 45125, 4545, 785413});
new MultilengthMultiseedNoDuplicatesTest(new int[]{50, 100, 1000}, new int[]{474854, 43233});
////// Passed! Bye bye.
System.out.println("Passed test suite "+this.getClass().getCanonicalName());
}
}
public static String stringfor(int[] array) {
StringBuilder sb = new StringBuilder();
build(sb, array);
return sb.toString();
}
public static void build(StringBuilder sb, int[] array) {
for (int i=0 ; i<array.length ; i++) {
if (sb.length()>0) sb.append(' ');
sb.append(array[i]);
}
}
public static String stringfor(double[] array) {
StringBuilder sb = new StringBuilder();
build(sb, array);
return sb.toString();
}
public static void build(StringBuilder sb, double[] array) {
for (int i=0 ; i<array.length ; i++) {
if (sb.length()>0) sb.append(' ');
sb.append(array[i]);
}
}
public static String stringfor(String[] labels) {
StringBuffer sb = new StringBuffer();
String sep = "" ;
for (int i=0 ; i<labels.length ; i++) {
sb.append(sep);
String label = labels[i] ;
sb.append(label!=null ? label : "null");
sep = ", " ;
}
return sb.toString();
}
}
Maybe not exactly for that case, but for those who looking for answer how to sort one array of String based on another:
// Array of values, in a order of sorting
static final Map<String, Integer> ROUNDS_SORT = new HashMap<String, Integer>();
static {
ROUNDS_SORT.put("f", 0);
ROUNDS_SORT.put("s", 1);
ROUNDS_SORT.put("q", 2);
ROUNDS_SORT.put("r16", 3);
ROUNDS_SORT.put("r32", 4);
ROUNDS_SORT.put("r64", 5);
}
// Your array to be sorted
static ArrayList<String> rounds = new ArrayList<String>() {{
add("f");
add("q");
add("q");
add("r16");
add("f");
}};
// implement
public List<String> getRoundsSorted() {
Collections.sort(rounds, new Comparator<String>() {
#Override
public int compare(String p1, String p2) {
return Integer.valueOf(ROUNDS_SORT.get(p1)).compareTo(Integer.valueOf(ROUNDS_SORT.get(p2)));
}
});
return rounds;
}
In java you need to have two arrays one copy to sort off and the array you want to sort.
with a lambda:
String[] strings = new String[]{"string1", "string2", "string3", "string4"};
final int[] ints = new int[]{100, 88, 92, 98};
final List<String> stringListCopy = Arrays.asList(strings);
ArrayList<String> sortedList = new ArrayList(stringListCopy);
Collections.sort(sortedList, (left, right) -> ints[stringListCopy.indexOf(left)] - ints[stringListCopy.indexOf(right)]);
Or with Comparator:
String[] strings = new String[]{"string1", "string2", "string3", "string4"};
final int[] ints = new int[]{100, 92, 88, 98};
final List<String> stringListCopy = Arrays.asList(strings);
ArrayList<String> sortedList = new ArrayList(stringListCopy);
Collections.sort(sortedList, Comparator.comparing(s -> ints[stringListCopy.indexOf(s)]));
Create an array of longs with the top 32 bits being the sorting integers and the bottom 32 bits being the array indexes. Sort that array then use the now sorted indexes to build a sorted string array.
String[] strings = new String[]{"string1", "string2", "string3"};
final int[] ints = new int[]{40, 32, 34};
final long[] longs = new long[ints.length];
for (int i = 0; i < ints.length; i++) {
longs[i] = (long)ints[i] << 32 | (long)i;
}
Arrays.sort(longs);
String[] sortedStrings = new String[strings.length];
for(int i = 0; i < longs.length; i++) {
sortedStrings[i] = strings[(int)longs[i]];
}
System.out.println(Arrays.asList(sortedStrings));
I believe this is algorithmically the same as Ofek's stream-based solution above, but uses more traditional Java.
A feature of the algorithm is that if two entries have the same sorting integer they will retain their original sequences with respect to each other.
Make a TreeMap<Integer, List<ObjectTypeFromA>> where the map key is the values in B, and the map values are the values in A (using a list to allow for duplicate keys). It will be sorted in the order of B by definition.
public static void main(String[] args) {
String[] strings = { "string1", "string2", "string3", "string4" };
int[] ints = { 40, 32, 32, 34 };
System.out.println(Arrays.toString(getSortedStringArray(strings, ints)));
}
public static String[] getSortedStringArray(String[] strings, int[] order) {
Map<Integer, List<String>> map = new TreeMap<>();
for (int i = 0; i < strings.length; i++) {
if (!map.containsKey(order[i])) {
map.put(order[i], new LinkedList<String>());
}
map.get(order[i]).add(strings[i]);
}
String[] ret = new String[strings.length];
int i = 0;
for (Map.Entry<Integer, List<String>> mapEntry : map.entrySet()) {
for (String s : mapEntry.getValue()) {
ret[i++] = s;
}
}
return ret;
}

Randomly select n items from a map

I am trying to randomly generate 'n' number of items from a HashMap where 'n' is determined by the user.
Here is what I have so far:
public static void main(String []args){
int numColors = 3;
HashMap<String, String> map = new HashMap<String, String>();
map.put("White","FFFFFF");
map.put("Blank","000000");
map.put("Red","ED0A15");
map.put("Green","06F76C");
map.put("Blue","0689FF");
map.put("Sky Blue","00C2FC");
map.put("Light Blue","08F0FC");
map.put("Silver","C0BFC5");
map.put("Mint","ABD3CA");
map.put("Off White","FFEFF0");
map.put("Purple","736FFA");
map.put("Lavendar","DEBEEF");
map.put("Hot Pink","F5159A");
map.put("Pink","DB39CC");
map.put("Light Pink","F5C2E3");
map.put("Blush","C95FA7");
map.put("Orange","D4361B");
map.put("Yellow","DEF231");
map.put("Warm White","F3E4C3");
map.put("Turquoise","01DCA4");
List<String> valuesList = new ArrayList<String>(map.values());
int randomIndex = new Random().nextInt(valuesList.size());
String randomValue = valuesList.get(randomIndex);
System.out.printf(randomValue);
}
It prints 1 random color for me (in hex) which I want, however I am unsure of how/which loop to use in order to generate say 3 random hex colors from the map. I declared numColors as 3 just to try and test this out.
Here is what I ended up going with:
public static void main(String []args){
int numColors = 3;
HashMap<String, String> map = new HashMap<String, String>();
map.put("White","FFFFFF");
map.put("Blank","000000");
map.put("Red","ED0A15");
map.put("Green","06F76C");
map.put("Blue","0689FF");
map.put("Sky Blue","00C2FC");
map.put("Light Blue","08F0FC");
map.put("Silver","C0BFC5");
map.put("Mint","ABD3CA");
map.put("Off White","FFEFF0");
map.put("Purple","736FFA");
map.put("Lavendar","DEBEEF");
map.put("Hot Pink","F5159A");
map.put("Pink","DB39CC");
map.put("Light Pink","F5C2E3");
map.put("Blush","C95FA7");
map.put("Orange","D4361B");
map.put("Yellow","DEF231");
map.put("Warm White","F3E4C3");
map.put("Turquoise","01DCA4");
List<String> keys = new ArrayList<String>(map.keySet());
Random rand = new Random();
for (int i = 0; i < numColors; i++) {
String key = keys.get(rand.nextInt(keys.size()));
System.out.println(map.get(key));
}
}
A simple solution is to shuffle the entire map using Collections.shuffle(map). Then just iterating over it and picking the first n elements.
Of course this doesn't make sense if the map is huge and you only need a couple of elements.
Edit:
Naturally, with this solution you won't get any duplicate entries
If I understand your question, you could do it with
List<String> keys = new ArrayList<String>(map.keySet());
Random rand = new Random();
for (int i = 0; i < numColors; i++) {
String key = keys.get(rand.nextInt(keys.size()));
System.out.println(map.get(key));
}
Changes are mentioned in comments
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
int numColors = 3;
HashMap<String, String> map = new HashMap<String, String>();
map.put("White", "FFFFFF");
map.put("Blank", "000000");
map.put("Red", "ED0A15");
map.put("Green", "06F76C");
map.put("Blue", "0689FF");
map.put("Sky Blue", "00C2FC");
map.put("Light Blue", "08F0FC");
map.put("Silver", "C0BFC5");
map.put("Mint", "ABD3CA");
map.put("Off White", "FFEFF0");
map.put("Purple", "736FFA");
map.put("Lavendar", "DEBEEF");
map.put("Hot Pink", "F5159A");
map.put("Pink", "DB39CC");
map.put("Light Pink", "F5C2E3");
map.put("Blush", "C95FA7");
map.put("Orange", "D4361B");
map.put("Yellow", "DEF231");
map.put("Warm White", "F3E4C3");
map.put("Turquoise", "01DCA4");
// scanner for accepting values
Scanner scan = new Scanner(System.in);
System.out.println("Enter number");
int N = scan.nextInt();
// random object for generating random values
Random rand = new Random();
// converting map values to list
List<String> valuesList = new ArrayList<String>(map.values());
for (int i = 1; i <= N; i++) {
// choose random value
int randomIndex = rand.nextInt(valuesList.size());
// get value
String randomValue = valuesList.get(randomIndex);
// printing
System.out.println("Random value " + i + " : " + randomValue);
}
}
}
To prevent duplicates you can do something like this :
// random object for generating random values
Random rand = new Random();
// converting map values to list
List<String> valuesList = new ArrayList<String>(map.values());
Set<String> set = new HashSet<String>();
while (set.size() != N) {
int randomIndex = rand.nextInt(valuesList.size());
String randomValue = valuesList.get(randomIndex);
set.add(randomValue);
}
System.out.println(set);
As Malt suggested, to prevent duplicates and keep code clean:
List<String> list = new ArrayList(map.values() );
Collections.shuffle(list);

Compare HashMap values in an ArrayList

I have an ArrayList and there are some HashMap<String, String> in this. So, I want to compare for same values in the maps. When I find same values then I want to keep one map of them. For example, consider that second map and fifth map (in the arraylist) have the same value. I want to keep the second map and remove the fifth from the arraylist.
i try to do with an iterator, but i can't do it. It seems complicated. Can you give me an example?
This is my last try:
private HashMap<String, String> mapValues = new HashMap<String, String>();
private HashMap<String, String> mapValues2 = new HashMap<String,String>();
private HashMap<Integer, String> mval = new HashMap<Integer, String>();
//i take the ArrayList with the maps for comparison private
ArrayList<HashMap<String, String>> check(ArrayList<HashMap<String, String>> list) {
//a new ArrayList. It will have the maps(HashMap<key, value>) with no same values.
ArrayList<HashMap<String, String>> listFinal = new ArrayList<HashMap<String, String();
for (int i = 0; i < list.size(); i++) {
mapValues = list.get(i);
mval.put(i, mapValues.get("value"));
}
for (int i = 0; i < mval.size(); i++) {
HashMap<String, String> newMapValues = new HashMap<String, String>();
mapValues2 = list.get(i);
String iVal = mapValues2.get("value");
newMapValues = list.get(i);
int flag = -1;
int remove = -1;
for (int j = i+1; j < mval.size()-1; j++) {
String jVal = mval.get(j);
if (val.compareTo(jVal) == 0) {
flag = i;
remove = j;
}
}
if (flag == -1) {
listFinal.add(newMapValues );
} else if (flag != -1) {
listFinal.remove(remove);
}
}
}
Just thinking out loud but my approach would be something like:
Create a Set, where you store the values that you already found in the map.
Each time you get a Map in a new position of the list, check if the element of the Map exists in the Set, if it does, remove the Map from the ArrayList (it's duplicated), if it doesn't, add the value of the Map to the Set and Carry on.
Make sure you remove the Map from the ArrayList using the Iterator's remove method!
List<Map<String, String>> mapList = new ArrayList<Map<String, String>>();
//... filling up list and maps...
Set<String> valueSet = new HashSet<String>();
for(Iterator<Map<String, String>> mapIt = mapList.iterator(); mapIt.hasNext();) {
final Map<String, String> map = mapIt.next();
boolean hasDuplicate = false;
for(final String mapValue : map.values()) {
if(valueSet.contains(mapValue))
hasDuplicate = true;
}
if(hasDuplicate)
mapIt.remove();
valueSet.addAll(map.values());
}
Hope someone proofreads this, cause I'm not typing it in an IDE and I haven't had my coffee yet.
EDIT: okay, that previous version was wrong as hell. Check this instead.
EDIT 2: just realized this won't work either. It might remove, say, map 3 because it has a dupe value with map 2, but map 2 is removed because of some other dupe value with map 1. Result: only map 1 is retained and map 2 and 3 are removed but map 3 doesn't have dupes with map 1. This is a bit more complex than I thought. Better get that coffee...
Create a Set<HashMap<String,String>> and add every member of list to it. Problem solved!
If you absolutely need an ArrayList instead of a Set, you can create a new ArrayList from the Set, but either way the lesson is: let Java do the work for you. You are unlikely to do a better job at collection manipulation than the standard library.
package com.test.examples;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.test.vo.CustomerContactVO;
import com.test.vo.CustomerOutPut;
import com.test.vo.CustomerPreferenceVO;
public class TestExampleOne {
public static Map<String, CustomerContactVO> getVO(){
Map<String, CustomerContactVO> contactVOMap = new HashMap<String, CustomerContactVO>();
CustomerContactVO v = new CustomerContactVO();
v.setContactAcctID("60011151");
v.setEmailID("raj#gmail.com");
CustomerContactVO v1 = new CustomerContactVO();
v1.setContactAcctID("60011152");
v1.setEmailID("raj1#gmail.com");
CustomerContactVO v2 = new CustomerContactVO();
v2.setContactAcctID("60011153");
v2.setEmailID("raj2#gmail.com");
CustomerContactVO v3 = new CustomerContactVO();
v3.setContactAcctID("60011154");
v3.setEmailID("raj3#gmail.com");
CustomerContactVO v4 = new CustomerContactVO();
v4.setContactAcctID("60011155");
v4.setEmailID("raj4#gmail.com");
contactVOMap.put("60011151", v);
contactVOMap.put("60011152", v1);
contactVOMap.put("60011153", v2);
contactVOMap.put("60011154", v3);
contactVOMap.put("60011155", v4);
return contactVOMap;
}
public static List<CustomerPreferenceVO> perfVo(){
CustomerPreferenceVO prefVo = new CustomerPreferenceVO();
prefVo.setContactAcctID("60011151");
prefVo.setMktInd("500");
prefVo.setPrefInd("Y");
CustomerPreferenceVO prefVo1 = new CustomerPreferenceVO();
prefVo1.setContactAcctID("60011153");
prefVo1.setMktInd("302");
prefVo1.setPrefInd("N");
CustomerPreferenceVO prefVo2 = new CustomerPreferenceVO();
prefVo2.setContactAcctID("60011154");
prefVo2.setMktInd("302");
prefVo2.setPrefInd("Y");
List<CustomerPreferenceVO> list = new ArrayList<CustomerPreferenceVO>();
list.add(prefVo);
list.add(prefVo1);
list.add(prefVo2);
return list;
}
public static void main(String[] args) {
Iterator<Entry<String, CustomerContactVO>> it = getVO().entrySet().iterator();
List<CustomerOutPut> customerOutPutsList = new ArrayList<CustomerOutPut>();
while(it.hasNext()){
Entry<String, CustomerContactVO> ent = it.next();
String contAcctIDKey = ent.getKey();
String email = ent.getValue().getEmailID();
CustomerOutPut customerOutPut = new CustomerOutPut();
customerOutPut.setContactAcctIDVo(contAcctIDKey);
customerOutPut.setEmailIDVo(email);
for (CustomerPreferenceVO customerPreferenceVO : perfVo()) {
if(customerPreferenceVO.getContactAcctID()!=null &&
customerPreferenceVO.getContactAcctID().equals(contAcctIDKey)){
customerOutPut.setContactAcctIDRef(customerPreferenceVO.getContactAcctID());
customerOutPut.setMktIndRef(customerPreferenceVO.getMktInd());
customerOutPut.setPrefIndRef(customerPreferenceVO.getPrefInd());
}
}
customerOutPutsList.add(customerOutPut);
}
for (CustomerOutPut customerOutPut : customerOutPutsList) {
System.out.println(customerOutPut.toString());
}
}
}
Compare Map keys with Arraylist values
public static void main(String[] args) {
Iterator<Entry<String, CustomerContactVO>> it = getVO().entrySet().iterator();
List<CustomerOutPut> customerOutPutsList = new ArrayList<CustomerOutPut>();
while(it.hasNext()){
Entry<String, CustomerContactVO> ent = it.next();
String contAcctIDKey = ent.getKey();
String email = ent.getValue().getEmailID();
CustomerOutPut customerOutPut = new CustomerOutPut();
customerOutPut.setContactAcctIDVo(contAcctIDKey);
customerOutPut.setEmailIDVo(email);
for (CustomerPreferenceVO customerPreferenceVO : perfVo()) {
if(customerPreferenceVO.getContactAcctID()!=null && customerPreferenceVO.getContactAcctID().equals(contAcctIDKey)){
customerOutPut.setContactAcctIDRef(customerPreferenceVO.getContactAcctID());
customerOutPut.setMktIndRef(customerPreferenceVO.getMktInd());
customerOutPut.setPrefIndRef(customerPreferenceVO.getPrefInd());
}
}
customerOutPutsList.add(customerOutPut);
}
for (CustomerOutPut customerOutPut : customerOutPutsList) {
System.out.println(customerOutPut.toString());
}
}

Categories

Resources