Counting the number of unique values in a vector - java

I have a method which takes in parameters in the form of a vector from another vector. This vector can be of the size 2, 3 or 4 elements.
I want to count the frequency of every word in that vector. For example, if the vector contained the strings : "hello", "my" , "hello" , I want to output an array that is
[2, 1] where 2 is the frequency of hello and 1 is the frequency of my.
Here is my attempt after reading a few questions on this website:
int vector_length = query.size();
int [] tf_q = new int [vector_length];
int string_seen = 0;
for (int p = 0; p< query.size(); p++)
{
String temp_var = query.get(p);
for (int q = 0; q< query.size(); q++)
{
if (temp_var == query.get(q) )
{
if (string_seen == 0)
{
tf_q[p]++;
string_seen++;
}
else if (string_seen == 1)
{
tf_q[p]++;
string_seen = 0;
query.remove(p);
}
}
}
}
System.out.print(Arrays.toString(tf_q));
What is the right direction to go?

Use a HashMap of type to track the unique string values you encounter that count each word
String[] vector // your vector
Map<String, Integer> stringMap = new HashMap<String, Integer>();
for (int i = 0; i < vector.length; i++) {
if (stringMap.containsKey(vector[i]) {
Integer wordCount = stringMap.get(vector[i]);
stringMap.put(vector[i], new Integer(wordCount + 1));
}
else {
stringMap.put(vector[i], new Integer(1));
}
}

String[] input = {"Hello", "my", "Hello", "apple", "Hello"};
// use hashmap to track the number of strings
HashMap<String, Integer> map = new HashMap<String, Integer>();
// use arraylist to track the sequence of the output
ArrayList<String> list = new ArrayList<String>();
for (String str : input){
if(map.containsKey(str)){
map.put(str, map.get(str)+1);
} else{
map.put(str, 1);
list.add(str); // if the string never occurred before, add it to arraylist
}
}
int[] output = new int[map.size()];
int index = 0;
for (String str : list){
output[index] = map.get(str);
index++;
}
for (int i : output){
System.out.println(i);
}
This should be your answer! Result is in "int[] output"

If you want to maintain the relation between each word and the frequency of that word, then I suggest that you use a HashMap instead. For example:
Map<String,Integer> histogram = new HashMap<String,Integer>();
for (String word : query)
{
Integer count = histogram.get(word);
if (count == null)
histogram.put(word,1);
else
histogram.put(word,count+1);
}
At this point, you can (for example) print each word with the corresponding frequency:
for (String word : histogram.keySet())
System.out.println(word+" "+histogram.get(word));
Or you can obtain an array which contains only the frequencies, if that's all you want:
Integer[] array = histogram.values().toArray(new Integer[histogram.size()]);
Or even a collection, which is just as useful and convenient as any native array:
Collection<Integer> collection = histogram.values();

Related

Java copy elements in column from String array to new int array

just after a bit of help with something that I cant seem to get right.
I have the following code which displays the values in a csv file. This is working.
while(file.hasNext()){
String data = file.nextLine();
String[] values = data.split(",");
for(String index : values){
System.out.printf("%s \t", index);
}
System.out.println();
}
The code displays:
1 John Smith Engineering
2 Jim Jones Cooking
I want to take the values just from values[0] (which are the ID's - 1,2) and copy them into a new int array so I can pass this to other methods to perform searches and whatnot. Any help would be greatly appreciated.
Thanks!
Not quite sure I understand your question fully, but you can try this:
String[] str_array = {...};
int[] int_array = {...};
int_array[index] = Integer.parseInt(str_array[index]);
This way you can add a String to an int array, watch out for NumberFormatExceptions.
Edit:
ArrayList<Integer> ids = new ArrayList<>(); // IDs: 1, 43, 23...
Scanner scanner = new Scanner(System.in); // Reading from console
int input = scanner.nextInt();
if (ids.contains(input)) {
// true
} else {
// false
}
Just save values[0] into a seperate list and convert it to an array. If you know the number of ids you can directly save your ids into an array.
List<String> ids = new ArrayList<>();
while (file.hasNext()) {
String data = file.nextLine();
String[] values = data.split(",");
if (values.length >= 1) {
ids.add(values[0]);
for (String index : values) {
System.out.printf("%s \t", index);
}
}
System.out.println();
}
String[] idsArray = new Integer[ids.size()];
ids = ids.toArray(idsArray);
// use idsArray
you can try this:)
Map<Integer, List<String>> map = new HashMap<Integer, List<String>>();
while(file.hasNext()){
String data = file.nextLine();
String[] values = data.split(",");
for(int key=0;key<values.size();key++){
if (!map.containsKey(key)){
map.put(key, new ArrayList<String>());
}
map.get(key).add(values[key]);
}
}
Integer[] items = new Integer[map.get(0).size()];
for (i = 0; i < map.get(0).size() ; i++) {
items[i]=Integer.valueOf(map.get(0).get(i));
}

Creating a HashMap of chars in a string and integers in an ArrayList<integer>

I have to create a HashMap that records the letters in a string and their index values in a ArrayList, so that if the HashMap is called with some string key, each related index integer is returned, and so that the map can be called by itself such that each key is shown with their indexes, For example for the string "Hello World", the map would look something like:
d=[9], o=[4, 6], r=[7], W=[5], H=[0], l=[2, 3, 8], e=[1].
I'm really confused by the requirement of the inputs as String and ArrayList, rather than chars and integers. Could you explain to me the relationship of the map to those objects, and to their components which are ultimately what are recorded as keys and values? When trying to debug, it stops processing before the map call.
The error message is:
java.lang.AssertionError: Wrong number of entries in Concordance. Expected: 5. Got: 1
Expected :1
Actual :5
But I really think I'm not grasping HashMap very well, so I'd appreciate if anyone could guide me through the basics, or provide anything educational about using HashMap, especially ones that use ArrayList.
public HashMap<String, ArrayList<Integer>> concordanceForString(String s) {
HashMap<String, ArrayList<Integer>> sMap = new HashMap<>();//create map "sMap"
char[] sArray = new char[s.length()]; //create character array, "sArray", for string conversion
ArrayList<Integer> sCharIndex = new ArrayList<Integer>();
for (int i = 0; i < s.length(); i++) {
sArray[i] = s.charAt(i); // convert string into array
}
for (int j = 0; j < sArray.length; j++){
sCharIndex.add(j); // add char indexes to index ArrayList
}
sMap.put(s, sCharIndex); //add the String and ArrayList
return sMap; // I feel like this should be sMap.get(s) but when I do, it gives me the zigzag red underline.
}
Here is a way to do it:
String input = "hello world";
Map<String, List<Integer>> letters = new HashMap<String, List<Integer>>();
// remove all whitespace characters - since it appears you are doing that
String string = input.replaceAll("\\s", "");
// loop over the length of the string
for (int i = 0; i < string.length(); i++) {
// add the entry to the map
// if it does not exist, then a new List with value of i is added
// if the key does exist, then the new List of i is added to the
// existing List
letters.merge(string.substring(i, i + 1),
Arrays.asList(i),
(o, n) -> Stream.concat(o.stream(), n.stream()).collect(Collectors.toList()));
}
System.out.println(letters);
that gives this output:
{r=[7], d=[9], e=[1], w=[5], h=[0], l=[2, 3, 8], o=[4, 6]}
EDIT - this uses a Character as the key to the map:
String input = "hello world";
Map<Character, List<Integer>> letters = new HashMap<Character, List<Integer>>();
String string = input.replaceAll("\\s", "");
for (int i = 0; i < string.length(); i++) {
letters.merge(string.charAt(i), Arrays.asList(i), (o, n) ->
Stream.concat(o.stream(), n.stream()).collect(Collectors.toList()));
}
System.out.println(letters);
Essentially, this is what you want to do.
This presumes a HashMap<String, List<Integer>>
List<Integer> sCharIndex;
for (int i = 0; i < s.length(); i++) {
// get the character
char ch = s.charAt(i);
if (!Character.isLetter(ch)) {
// only check letters
continue;
}
ch = ch+""; // to string
// get the list for character
sCharIndex = sMap.get(ch);
// if it is null, create one and add it
if (sCharIndex == null) {
// create list
sCharIndex = new ArrayList<>();
// put list in map
sMap.put(ch, sCharIndex);
}
// at this point you have the list so
// add the index to it.
sCharIndex.add(i);
}
return sMap;
A hashMap is nothing more than a special data structure that takes an object as a key. Think of an array that takes a digit as an index and you can store anything there.
A hashMap can take anything as a key (like an index but it is called a key) and it can also store anything.
Note that your key to hashMap is a String but you're using a character which is not the same. So you need to decide which you want.
HashMap<String, List<Integer>> or HashMap<Character, List<Integer>>
There are also easier ways to do this but this is how most would accomplish this prior to Java 8.
Here is a much more compact way using streams. No loops required.
Map<String, List<Integer>> map2 = IntStream
.range(0,s.length())
// only look for letters.
.filter(i->Character.isLetter(s.charAt(i)))
.boxed()
// stream the Integers from 0 to length
// and group them by character in a list of indices.
.collect(Collectors.groupingBy(i->s.charAt(i)+""));
But I recommend you become familiar with the basics before delving into streams (or until your instructor recommends to do so).
For more information check out The Java Tutorials
Check out this code :
public static void main(String []args){
//Create map of respective keys and values
HashMap<Character, ArrayList<Integer>> map = new HashMap();
String str = "Hello world"; //test string
int length = str.length(); //length of string
for(int i = 0; i < length; i++){
ArrayList<Integer> indexes = new ArrayList(); //empty list of indexes
//character of test string at particular position
Character ch = str.charAt(i);
//if key is already present in the map, then add the previous index associated with the character to the indexes list
if(map.containsKey(ch)){
//adding previous indexes to the list
indexes.addAll(map.get(ch));
}
//add the current index of the character to the respective key in map
indexes.add(i);
//put the indexes in the map and map it to the current character
map.put(ch, indexes);
}
//print the indexes of 'l' character
System.out.print(map.get('l'));
}
The code is self explanatory.
public class Array {
public static void main(String[] args) {
printSortedMap(concordanceForString("Hello world")); // r[7] d[9] e[1] w[5] H[0] l[2, 3, 8] o[4, 6]
}
public static HashMap<String, ArrayList<Integer>> concordanceForString(String s) {
HashMap<String, ArrayList<Integer>> sMap = new HashMap<>();
String str = s.replace(" ", "");
for (int i = 0; i < str.length(); i++) {
ArrayList<Integer> sCharIndex = new ArrayList<Integer>();
for (int j = 0; j < str.length(); j++) {
if ( str.charAt(i) == str.charAt(j) ) {
sCharIndex.add(j);
}
}
sMap.put(str.substring(i,i+1), sCharIndex);
}
return sMap;
}
public static void printSortedMap(HashMap<String, ArrayList<Integer>> sMap) {
for (Map.Entry<String, ArrayList<Integer>> entry : sMap.entrySet()) {
System.out.println(entry.getKey() + entry.getValue());
}
}

Grouping the nested loop elements based on the first iteration variable in Java

I have 2 lists one for the sentence one for the keywords. The idea is to check if the sentence have the keywords. and put them in a list for each sentence in order.
I am sorry if this is already duplicated here in advance.
List <String> sentence= new ArrayList <>();
sentence.add("this is a good dog");
sentence.add("cats drink milk");
sentence.add("Animals are beautiful creatures");
List <String> keyword= new ArrayList <>();
keyword.add("dog");
keyword.add("cats");
keyword.add("beautiful");
keyword.add("good");
keyword.add("are");
keyword.add("this");
keyword.add("milk");
My idea was to create 2 nested loops for each list:
for (int b = 0; b < sentence.size(); b++) {
for (int c = 0; c < keyword.size(); c++) {
if (sentence.get(b).contains(keyword.get(c))) {
System.out.println(keyword.get(c));
}
}
}
The output of this is:
dog
good
this
cats
milk
beautiful
are
The desired output would be:
[this,good,dog]
[cats,milk]
[are,beautiful]
So it is like getting all the existing keywords, in the order of the sentence,not related to keywords order.
and then group the existing keywords for each sentence, as in the order of existence.
Hope it is clear. Would really appreciate any ideas. doesnt have to follow the same method.
Iterate over your sentence list. For each sentence iterate over your keyword list. Add each found keyword found in a tempList, sort the tempList by the index of keyword in sentence and finally add each tempList to a list of lists. Example:
public static void main(String[] args) {
List <String> sentence= new ArrayList <>();
sentence.add("this is a good dog");
sentence.add("cats drink milk");
sentence.add("Animals are beautiful creatures");
List <String> keyword= new ArrayList <>();
keyword.add("dog");
keyword.add("cats");
keyword.add("beautiful");
keyword.add("good");
keyword.add("are");
keyword.add("this");
keyword.add("milk");
List<List<String>> result = new LinkedList<>();
for(String sen: sentence){
List<String> tempList = new ArrayList<>();
for(String key: keyword){
if(sen.contains(key)){
tempList.add(key);
}
}
tempList.sort(new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
return sen.indexOf(o1) - sen.indexOf(o2) ;
}
});
result.add(tempList);
}
for(List<String> r : result){
System.out.println(r);
}
}
You need a slight modification in your looping
for (int i = 0; i < sentence.size(); i++) {
String[] matchArray = new String[sentence.get(i).split(" ").length];
for (int j = 0; j < keyword.size(); j++) {
if (sentence.get(i).contains(keyword.get(j))) {
matchArray[Arrays.asList(sentence.get(i).split(" ")).indexOf(keyword.get(j))] = keyword.get(j);
}
}
List<String> matchList = new ArrayList<String>();
for(String match: matchArray) {
if(match != null) {
matchList.add(match);
}
}
System.out.println(matchList);
}
For every sentence create an array with size same as the sentence (just to ensure size). Now when matches are found get the index of the match from sentence and add element to that particular index of the array. So at the end of keyword iteration you will have all matches in array with null values if some words are not matching.
Now declare a new List of String into which add the elements from array which are not null. At last print the list.
I think Map would be a good choice here. Just make sentences keys for the map and keywords as value. Following is the code for the same.
Map <String, ArrayList<String>> sentences= new HashMap<>();
sentences.put("this is a good dog", new ArrayList<>());
sentences.put("cats drink milk", new ArrayList<>());
sentences.put("Animals are beautiful creatures", new ArrayList<>());
List <String> keyword= new ArrayList <>();
keyword.add("dog");
keyword.add("cats");
keyword.add("beautiful");
keyword.add("good");
keyword.add("are");
keyword.add("this");
keyword.add("milk");
keyword.forEach(word -> sentences.entrySet().stream()
.filter(map -> map.getKey().contains(word)).
forEach(map -> sentences.computeIfAbsent(map.getKey(), key->new ArrayList<>()).add(word)));
sentences.forEach((key, value) -> System.out.println(value));
Try something like this:
for (String sen: sentence) {
System.out.print("[");
boolean first = true;
for (String word: sen.split("[\\s\\p{Punct}]")) {
if (keyword.contains(word)) {
if (first) {
first = false;
} else {
System.out.print(",");
}
System.out.print(word);
}
}
System.out.println("]");
}
this should do it, printing exactly in the format you requested :
for (int b = 0; b < sentence.size(); b++) {
String arr[] = sentence.get(b).split("\\s+");
List result = new ArrayList<>();
for (int c = 0; c < arr.length; c++ ) {
if (keyword.contains(arr[c]))
result.add(arr[c]);
}
System.out.println(result);
}
I would use the following :
for(String currentSentence : sentence) {
List<String> keywordsInSentence = new ArrayList<>();
for (String word : currentSentence.split("\\s+")) {
if (keyword.contains(word)) {
keywordsInSentence.add(word);
}
}
System.out.println(keywordsInSentence);
}
You can try it here.
(and I'd rename sentence into sentences or sentenceList and similarly for keyword, otherwise it's just confusing)
If you need to do anything more to the keywords than immediately displaying them, you could insert the keywordsInSentence lists into a Map<String, List<String>> you would value by replacing the System.out.println by map.put(currentSentence, keywordsInSentence).

Apply a Frequency to an Element in an Array

I am trying to make a script that will take a set of Words (custom class), organize them alphabetically into an array by their text value (this part works). From here I was going to count how many terms ahead of it are the same as it, and that will be the frequency for all those similar terms. Then it continues to do this till each element in the array has been assigned a frequency. From here it re sorts the elements back into their original position provided a pre stored variable that holds their original element order. Here is the code:
public void setFrequencies() {
List<Word> dupeWordList;
dupeWordList = new ArrayList<>(wordList);
dupeWordList.removeAll(Collections.singleton(null));
Collections.sort(dupeWordList, (Word one, Word other) -> one.getValue().compareTo(other.getValue()));
int count;
int currElement;
for(currElement = 0; currElement < dupeWordList.size(); currElement++) {
count = 1;
Word tempWord = dupeWordList.get(currElement);
tempWord.setFrequency(count);
if(currElement+1 <= dupeWordList.size() - 1) {
Word nextWord = dupeWordList.get(currElement+1);
while(tempWord.getValue().equals(nextWord.getValue())) {
count++;
currElement++;
tempWord.setFrequency(count);
for(int e = 0; e < count - 1; e++) {
Word middleWord = new Word();
if(currElement-count+2+e < dupeWordList.size() - 1) {
middleWord = dupeWordList.get(currElement-count+2+e);
}
middleWord.setFrequency(count);
}
if(currElement+1 <= dupeWordList.size() - 1) {
nextWord = dupeWordList.get(currElement+1);
} else {
break;
}
}
break;
}
}
List<Word> reSortedList = new ArrayList<>(wordList);
Word fillWord = new Word();
fillWord.setFrequency(0);
fillWord.setValue(null);
Collections.fill(reSortedList, fillWord);
for(int i = 0; i < dupeWordList.size(); i++) {
Word word = dupeWordList.get(i);
int wordOrder = word.getOrigOrder();
reSortedList.set(wordOrder, word);
}
System.out.println(Arrays.toString(DebugFreq(reSortedList)));
setWordList(reSortedList);
}
public int[] DebugFreq(List<Word> rSL) {
int[] results = new int[rSL.size()];
for(int i=0; i < results.length; i++) {
results[i] = rSL.get(i).getFrequency();
}
return results;
}
As you can see I set up a little debug method at the bottom. When I run this method is shows that every word was given a frequency of 1. I cant see the issue in my code, nor does it get any errors. Keep in mind I have had it display the sorted dupeWordList and it does correctly alphabetize and their are consecutive duplicate elements in it so this should not be happening.
So If I understand you correctly.. below code would be your solution.
Okay You have a list which is having a strings (terms or words) which are sorted in alphabetical Order.
// Okay the below list is already sorted in alphabetical order.
List<String> dupeWordList = new ArrayList<>(wordList);
To count the Frequency of words in your list, Map<String, Integer> might help you as below.
//Take a Map with Integer as value and String as key.
Map<String,Integer> result = new HashMap<String,Integer> ();
//Iterate your List
for(String s : dupeWordList)
{
if(map.containskey(s))
{
map.put(s,map.get(s)+1);
// Please consider casting here.
}else
{
map.put(s,1);
}
}
Okay now we have a map which is having the frequency of your words or terms as value in your map.
Hope it helps.

pairs of numbers that have a difference of K

This was my online interview question, and I already submitted the answer. However, the compilation was terminated due to time so I just submitted. Could I get feedback from you? Thanks in advance.
Problem:
Given N numbers , [N<=10^5] we need to count the total pairs of numbers that have a difference of K
Input Format:
1st line contains N & K (integers).
2nd line contains N numbers of the set. All the N numbers are assured to be distinct.
Output Format:
One integer saying the no of pairs of numbers that have a diff K.
Sample Input #00:
5 2
1 5 3 4 2
Sample Output #00:
3
My code:
import java.io.*
import java.util.*;
public class DiffNumbers {
public static void main(String[] args) throws Exception {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String line1 = in.readLine();
String line2 = in.readLine();
int n = Integer.parseInt(line1.split(" ")[0]);
int diff = Integer.parseInt(line1.split(" ")[1]);
Hashtable table = new Hashtable();
int[] arr = new int[n];
for(in i=0; i<n; i++) {
arr[i] = Integer.parseInt(line2.split(" ")[i]);
table.put(Integer.parseInt(line2.split(" ")[i]));
}
int count = 0;
for(in i=0; i<n; i++) {
if(table.containsKey(arr[i]+diff) {
count++;
}
}
system.out.println(count);
}
}
Using HashMap/Table needs extra space. If you want to avoid it you can do it this way
1) Sort the array
2) initialize outputCount as 0
3) Let there be two pointers. "first" start with 0 and "Other" pointer start with 1.
4)
while(arr[other]-arr[first] <requiredDifference)
other ++;
if(arr[other]-arr[first] == requiredDifference)
outputCount++;
else // no match for arr[first]
first++;
5)
return outputCount;
explanation :-
When difference is more than requiredDifference you stop moving ahead "other" poiner. So there is no match for arr[first]. So move ahead first counter. Now do the same logic for new arr[first]. This time you will continue checking from current position of "other" as array is sorted; lower number will not have required match.
public static void main(String[] args) throws Exception{
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String line1 = in.readLine();
String line2 = in.readLine();
int diff = Integer.parseInt(line1.split(" ")[1]);
Map<Integer, Object> nMap = new HashMap<Integer, Object>();
Map<Integer, Boolean> uMap = new HashMap<Integer, Boolean>();
Map<Integer, Boolean> lMap = new HashMap<Integer, Boolean>();
String[] numbers = line2.split(" ");
//init maps
for(String number : numbers){
Integer intValue = Integer.valueOf(number);
nMap.put(intValue, new Object()); //original set, N
uMap.put(intValue + diff, false); //upper-bound map
lMap.put(intValue - diff, false); //lower-bound map
}
int count = 0;
for(Integer nKey : nMap.keySet()){
//Do if the lower-bound of n exists in N and if n hasn't used as an upper-bound?
if(nMap.get(nKey - diff) != null && !uMap.get(nKey)){
count++;
//Mark the lower-bound as used.
lMap.put(nKey - diff, true);
}
//Do if the upper-bound of n exists in N and if n hasn't used as an lower-bound?
if(nMap.get(nKey + diff) != null && !lMap.get(nKey)){
count++;
//Mark the upper-bound as used.
uMap.put(nKey + diff, true);
}
}
System.out.println(count);
}
There's not much reason to store the integers in both an array and a hashtable. We can modify your code to do the all of the work in a single for loop.
for(int i=0; i<n; i++) {
int j = Integer.parseInt(line2.split(" ")[i]) //probably not how I would go about this
table.put(j);
if(table.containsKey(j+diff)) {
count++;
}
if(table.containsKey(j-diff)) {
count++;
}
}

Categories