Map elements in a list to positions in another list - java

Imagine we have two lists and want to know the postions of elements from one list in the other. To illustrate:
List<String> one = Arrays.asList("B", "I", "G");
List<String> another = Arrays.asList("L", "A", "R", "G", "E");
Result would be:
[-1, -1, 3]
because neither B nor I occur in second list, but G does on 3rd position.
This is what I came with so far:
<E> List<Integer> indices(List<E> elements, List<E> container) {
List<Integer> indices = new ArrayList<>(elements.size());
for (int i = 0; i < elements.size(); i++) {
indices.add(container.indexOf(indices.get(i)));
}
return indices;
}
Is there a faster solution that avoids internal loop in List.indexOf()?

You can use Map:
Map<String, Integer> otherMap = new HashMap<>(other.size());
int index = 0;
for(String otherElem : other) {
otherMap.put(otherElem, index++);
}
And then:
for(String oneElem : one) {
Integer index = otherMap.get(oneElem);
indices.add(index == null ? -1 : index);
}
Doing so, you get the index directly instead of iterating on a potentially very big list each time you look for and index.

You can use a HashMap<String, Integer> that would map every character to its position. Then use HashMap method .containsKey() to find out, if a certain String is present in the field and .get() to find out the position.
HashMap<String, Integer> another;
for (String str : one) {
if (another.contains(str)) {
result.add(another.get(str));
} else {
result.add(-1);
}
}

Related

Top K Frequent Elements - How to Reverse Elements

I've included a picture of the problem below that explains it in more detail. The goal is to just find the k highest occurrences in a dictionary of words. My approach is getting the frequency in a HashMap and then using a Priority Queue to store the max k elements. I then add the max k elements to my return list and return it.
For the given input in the picture, my code returns to correct output -
["i","love"]. The problem is for inputs like the one below:
input: ["the", "day", "is", "sunny", "the", "the", "the", "sunny", "is", "is"]
output: ["day","sunny","is","the"]
expected: ["the","is","sunny","day"]
The correct answer would just be a reverse of my current string, however if I reverse the string before returning the original input (the one in the picture) no longer works.
I think this had something to do with how the values are being store in the priority queue when their frequency is the same...but I'm not sure of to check for that.
Any thoughts on how I could fix this?
class Solution {
public List<String> topKFrequent(String[] words, int k) {
HashMap<String, Integer> map = new HashMap<>();
List<String> mostFrequent = new ArrayList<>();
for(int i = 0; i < words.length; i++) {
if(map.containsKey(words[i])) {
map.put(words[i], map.get(words[i]) + 1);
}
else {
map.put(words[i], 1);
}
}
PriorityQueue<String> pq = new PriorityQueue<String>((a,b) -> map.get(a) - map.get(b));
for(String s : map.keySet()) {
pq.add(s);
if(pq.size() > k) {
pq.remove();
}
}
for(String s : pq) {
mostFrequent.add(s);
}
//Collections.reverse(mostFrequent);
return mostFrequent;
}
}
One way to achieve is by changing your code like below,
class Solution {
public static List<String> topKFrequent(String[] words, int k) {
HashMap<String, Integer> map = new HashMap<>();
List<String> mostFrequent = new ArrayList<>();
for(int i = 0; i < words.length; i++) {
if(map.containsKey(words[i])) {
map.put(words[i], map.get(words[i]) + 1);
}
else {
map.put(words[i], 1);
}
}
//Below I am sorting map based on asked condition and storing it into the list.
List<Map.Entry<String,Integer>> sorted = new ArrayList<>(map.entrySet());
Collections.sort(sorted,(Map.Entry<String,Integer> x,Map.Entry<String,Integer> y) -> x.getValue().compareTo(y.getValue()) == 0? x.getKey().compareTo(y.getKey()):x.getValue().compareTo(y.getValue()) > 0 ? -1 : 1 );
for(Map.Entry<String,Integer> e : sorted) {
mostFrequent.add(e.getKey());
}
return mostFrequent;
}
Here, after creating the frequency map I am sorting them based on frequency and creating one new ArrayList.
You almost did it. But you have a few bugs.
At first, your solution is not full. In original task they asked not only about frequency but additional, if frequency is equal - output elements in alphabetical order.
To achieve that you can use following comparator for PriorityQueue:
PriorityQueue<String> pq = new PriorityQueue<String>((a, b) -> {
int countComparison = Integer.compare(map.get(a), map.get(b));
if (countComparison == 0)
return b.compareTo(a);
return countComparison;
});
And, the next mistake with your solution is iterating over PriorityQueue. PriorityQueue iterator does not guarantee any particular order. From the Javadocs
The Iterator provided in method iterator() is not guaranteed to traverse the elements of the priority queue in any particular order.
Because of it you need to poll elements from the queue. And part responsible for it:
while(!pq.isEmpty()) {
String s = pq.poll();
mostFrequent.add(s);
}
And final part - because of the order of elements in queue(from the lowest to the highest) you need to reverse output array:
Collections.reverse(mostFrequent);
The final solution will look like this:
public List<String> topKFrequent(String[] words, int k) {
HashMap<String, Integer> map = new HashMap<>();
List<String> mostFrequent = new ArrayList<>();
for(int i = 0; i < words.length; i++) {
if(map.containsKey(words[i])) {
map.put(words[i], map.get(words[i]) + 1);
}
else {
map.put(words[i], 1);
}
}
PriorityQueue<String> pq = new PriorityQueue<String>((a, b) -> {
int countComparison = Integer.compare(map.get(a), map.get(b));
if (countComparison == 0)
return b.compareTo(a);
return countComparison;
});
for(String s : map.keySet()) {
pq.add(s);
if(pq.size() > k) {
pq.remove();
}
}
while(!pq.isEmpty()) {
String s = pq.poll();
mostFrequent.add(s);
}
Collections.reverse(mostFrequent);
return mostFrequent;
}

How to put List elements to String Array in Java

Is there a way to put list elements to a String array in java? I sorted a Map by value using a custom Comparator and now trying to put the key(String) elements into an array. The only way I found is looping through the array and the sorted list at the same time and fill up the array that way but it only puts the last element into it.
Example:
My map without sorting: {a=5, b=2, c=8, d=1}
After sorted with custom Comparator: [c=8, a=5, b=2, d=1]
Now I simply need to put the key values (c,a etc.) to the tuple final String[] lettersWithBigValues = new String[n] where n is the length of the tuple.
However, after:
for (int i = 0; i < Integer.parseInt(args[1]); i++) {
System.out.println(lettersWithBigValues[i]+",");
}
The console gives back:
d,d,d,d given that the console line argument is 4
Here is the full function:
public String[] getTopLettersWithValues(final int n){
final String[] lettersWithBigValues = new String[n];
final Map<String, Integer> myMap = new HashMap<>();
int counter = 0;
for (final List<String> record : records) {
if (!myMap.containsKey(record.get(1))) {
myMap.put(record.get(1), counter += Integer.parseInt(record.get(4)));
} else {
myMap.computeIfPresent(record.get(1), (k,v) -> v + Integer.parseInt(record.get(4)));
}
}
System.out.println(myMap);
List<Map.Entry<String, Integer>> sorted = new LinkedList<>(myMap.entrySet());
// Sort list with list.sort(), using a custom Comparator
sorted.sort(valueComparator);
System.out.println(sorted);
for (int i = 0; i < lettersWithBigValues.length; i++) {
for (Map.Entry<String, Integer> values: sorted) {
lettersWithBigValues[i] = values.getKey();
}
}
return lettersWithBigValues;
}
Where records is a List of data read from a csv file.
And here is the comparator:
public Comparator<Map.Entry<String, Integer>> valueComparator = (o1, o2) -> {
Integer v1 = o1.getValue();
Integer v2 = o2.getValue();
return v2.compareTo(v1);
};
You can attain the array of keys as follows:
String [] lettersWithBigValues = myMap.entrySet().stream() // entries of your intial map
.sorted(valueComparator) // sorted by your comparator
.map(Map.Entry::getKey) // mapped to only the key e.g. 'd', 'a'
.toArray(String[]::new); // converted to array
Seems to me that you have mistakenly used a nested for loop, you just need the one:
for (int i = 0; i < lettersWithBigValues.length; i++) {
lettersWithBigValues[i] = sorted.get(i).getKey();
}
That would return the array: c, a, b, d
As an added suggestion you could also have created the Comparator using the Entry.comparingByValue() method.
Comparator<Entry<String,Integer>> valueComparator =
Entry.<String,Integer>comparingByValue().reversed();
It returns a ready made Comparator that compares by the natural order of the value. So to sort in reverse, you just need to tag on the reversed() method which is defined in the Comparator interface.

How do I break this array into sub-array(at continuous position) of similar type of alphabets

For eg.,
the input array is :
String array = {"0","0","0","K","K","B","P","P","P","Z",
"Z","D","D","E","E","F","N","O","O}
Output:
first sub-array = {"O,O,O"}
second sub-array = {"K","K"}
third sub-array = {"O","O"}
You can do this using stack for that checkout below code for that.
String data[] = { "0", "0", "0", "K", "K", "B", "P", "P", "P", "Z", "Z", "D", "D", "E", "E", "F", "N" };
// a = ['0','0','0','K','K','P','P','P','Z']
Stack<String> stack = new Stack<String>();
String prevValue = data[0];
for (int i = 1; i < data.length; i++) {
if (data[i].equals(data[i - 1])) {
prevValue = prevValue + data[i];
} else {
stack.push(prevValue);
prevValue = data[i];
}
}
stack.push(prevValue);
System.out.println(stack);
Assuming you don't know how many different characters you're looking for one possible solution would be using a Map:
Map<String,List<String>> map = new HashMap<>();
for(int i = 0; i < array.length; i++){
if(map.containsKey(array[i])
map.get(array[i]).add(array[i]);
else
map.put(array[i],array[i]);
}
However, personally I think what you're asking can be simplified with a Parameter style approach. This is, instead of storing each ocurrence of each string pattern you're looking for, you simply store a counter. So, and still assuming that you don't know how many distinct patterns you're looking for,you could do this:
Map<String,Integer> map = new HashMap<>();
for(int i = 0; i < array.length; i++){
map.put(array[i], new Integer(map.get(array[i]).intValue() + 1);
}
You can create a map with string as index and integer as value.
Then you can loop this array and assign the values of array as index of the map and keep increasing the integer value.
For example, you can add these lines inside the loop, and you will have a map:
Map<String, Integer> myCharMap = new HashMap<String, Integer>();
myCharMap.put(array[index], new Integer(myCharMap.get(array[index]).intValue()+1));
If you're looking for continuous regions, you can use looping since the order matters.
List<List<String>> continuous = new ArrayList<>();
List<String> current;
String last = null;
for(String s: array){
if(!s.equals(last)){
current = new ArrayList<>();
continuous.add(current);
}
current.add(s);
last=s;
}
In your example, you could use a stream and the grouping by collector since the regions are also unique characters.
Map<String, List<String>> grouped = Arrays.stream(array).collect(
Collectors.groupingBy(String::toString)
);
If you really need the String[] instead of List, you can use List.toArray.
String[] arr_version = grouped.get("0").toArray(new String[0]);

Java ArrayList sort two lists in same order

I have two ArrayLists in Java. Both lists are unsorted.
ArrayList<Integer> listOne = new ArrayList<>();
listOne.add(2);
listOne.add(1);
listOne.add(4);
listOne.add(8);
listOne.add(6);
ArrayList<String> listTwo = new ArrayList<>();
listTwo.add("ant");
listTwo.add("bear");
listTwo.add("cat");
listTwo.add("dog");
listTwo.add("zebra");
I want to sort listOne in natural order and each item of listTwo should be sorted according to the position in listOne:
What I have so far is:
Collections.sort(listOne);
for (int i = 0; i < listOne.size(); i++) {
int intTest = listOne.get(i);
String stringTest = listTwo.get(i);
System.out.println(intTest);
System.out.println(stringTest);
}
This prints :
1 ant, 2 bear, 4 cat , 6 dog , 8 zebra
My expected print output is:
1 bear, 2 ant, 4 cat, 6 zebra, 8 dog
So that when the item of listOne "1", that changed the position from 2nd to 1st, the item "bear" in listTwo, that was on the 2nd position, should also print on the 1st position.
What would be the most simple and efficient way to do this?
Create an ordered list of indices:
int n = listOne.size();
assert n == listTwo.size();
Integer[] indices = new Integer[n];
for (int i = 0; i < n; ++i) {
indices[i] = i;
}
Sort that list using a comparator that compares indices by looking at the corresponding elements in listOne.
Arrays.sort(
indices,
new Comparator<Integer>() {
public int compare(Integer a, Integer b) {
return listOne.get(a).compareTo(listOne.get(b));
}
});
Now you can use indices to reorder both lists:
static <T> void reorder(Integer[] indices, List<T> mutatedInPlace) {
List<T> tempSpace = new ArrayList<T>(indices.length);
for (int index : indices) {
tempSpace.add(mutatedInPlace.get(index);
}
mutatedInPlace.clear();
mutatedInPlace.addAll(tempSpace);
}
reorder(indices, listOne);
reorder(indices, listTwo);
TreeMap best suits this situation. It inserts the data in sorted order so basically store the key and against each key you can store the animal.
Map<Integer,String> sortedMap = new TreeMap<Integer,String>();
sortedMap.push(listOne.get(i),listTwo.get(listOne.get(i)));
In case you want to stick to ArrayList, you can iterate over the listOne and push it in HashMap<Integer,String>
iterate over list (for example i)
map.put( listOne.get(i), secondList.get(i));
So the hashMap would be like (2, "ant");
Collections.sort(listOne);
Against each entry, you can get the corresponding animal from map
We can use HashMap data structure, It contains “key-value” pairs and allows retrieving the value by key.
int i = 0;
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Here we’re storing the items from listOne as keys and their position as a value in the HashMap.
for (Integer num : listOne) {
map.put(num, i);
i++;
}
We’re printing the elements from listTwo as per the items from the listOne changed their position.
Collections.sort(listOne);
for (Integer num : listOne) {
System.out.println(num + " " + listTwo.get(map.get(num)));
}
One Solution:
int i = 0;
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (Integer num : listOne) {
map.put(num, i);
i++;
}
Collections.sort(listOne);
for (Integer num : listOne) {
System.out.println(num + " " + listTwo.get(map.get(num)));
}
Output is:
1 bear,
2 ant,
4 cat,
6 zebra,
8 dog
If you use a Map<Integer, String> for this, you don't even need to sort it if you take the TreeMap implementation.
It basically works as follows:
public class StackoverflowMain {
public static void main(String[] args) {
// initialize a map that takes numbers and relates Strings to the numbers
Map<Integer, String> animals = new TreeMap<Integer, String>();
// enter ("put" into the map) the values of your choice
animals.put(2, "ant");
animals.put(1, "bear");
animals.put(4, "cat");
animals.put(8, "dog");
animals.put(6, "zebra");
// print the whole map using a Java 8 forEach statement
animals.forEach((index, name) -> System.out.println(index + ": " + name));
}
}
This code will output
1: bear
2: ant
4: cat
6: zebra
8: dog
Putting the suggestions of all the friendly and helpful people together (plus some other research and test), here is the final code I came up with:
ArrayList<String> listOne = new ArrayList<>();
listOne.add("one");
listOne.add("eight");
listOne.add("three");
listOne.add("four");
listOne.add("two");
ArrayList<String> listTwo = new ArrayList<>();
listTwo.add("ant");
listTwo.add("bear");
listTwo.add("cat");
listTwo.add("dog");
listTwo.add("zebra");
Map<String, String> sortedMap = new TreeMap<String, String>();
for (int i = 0; i < listOne.size(); i++) {
String stringkey = listOne.get(i);
String stringValue = listTwo.get(i);
sortedMap.put(stringkey, stringValue);
}
print output = {eight=bear, four=dog, one=ant, three=cat, two=zebra}

It puts wrong null value from String array in HashMap

i am a newbie in Java (coming from JavaScript developing on Adobe LiveCycle) and facing the following problem:
I have a String array with several items. I want to put only the items with the value "a" to a HashMap. But instead of 3 "a" values in the HashMap i get 1 null value there. Why is that?
String[] s = {"a", "a", "b", "a"};
Map m = new HashMap();
for (int i = 0; i < s.length; i++) {
if (s[i].equals("a")) {
m.put(i, s[i]);
}
}
for (int i = 0; i < m.size(); i++) {
System.out.println(m.get(i));
}
// Prints
//a
//a
//null
You are putting the items in the map with key 0, 1 and 3.
You are taking them out with key 0, 1, an 2.
Use:
for (Object o : m.keySet()) {
System.out.println(m.get(o));
}
or - better:
Map<Integer, String> m = new HashMap<>();
...
for (Integer i : m.keySet()) {
System.out.println(i + " -> " + m.get(i));
}
You put the items with their corresponding index in array s in the Map, i.e. you have a Map with content {0=a, 1=a, 3=a}. Therefore if you try to access the map with key 2 (m.get(2)), you get a null since key 2 is not found in m.
Instead of using a for-loop over m's size, I recommend iteration over m's keySet() via a foreach-loop:
for (Object key : m.keySet()) {
System.out.println("key: " + key + ", value: " + m.get(key));
}
On a sidenote: you are using raw types. You should bind the types of the Map and HashMap properly (see the Javadoc of Map for details): Map<Integer, String> m = new HashMap<Integer, String>();. With properly bound types, key in the for-loop can be of type int or Integer. I recommend type Integer to avoid unnecessary Auto(un)boxing.
Your code is working correctly, but you are accessing it not correctly.
String[] s = {"a", "a", "b", "a"};
for (int i = 0; i < s.length; i++) {
if (s[i].equals("a")) {
m.put(i, s[i]);
}
}
This puts it like this
First iteration : m.put(0, "a");
Second iteration : m.put(1, "a");
Third iteration : "b" doest not equal "a" but still counts the index i up
Fourth iteration: m.put(3, "a");
Apart from the other answers you can still use your range based loop and access it with an Iterator
Iterator<String> it = m.values().iterator();
while (it.hasNext()) {
System.out.println(it.next());
}

Categories

Resources