I have an object, named objectOne, which each of its row contain 3 variables (String var1, String var2, int var3). So for each row, the data should be var1;var2;var3
My question is how to count frequency based on its object and its variable-in-object ? because code like int occurrences = Collections.frequency(list, item); cannot get its occurrences for a specific variable-in-object.
For example i have
objectOne :
is;is;125
that;is;861
you;are;90
that;is;469
I want to get how many occurrence of is word in var2 column (which the answer should be 3) and how many occurrence of that word in var1 column (which the answer should be 2) ?
Any help will be appreciated :)
I would implement the logic for finding the frequency by myself in the class as no direct API that exists for this purpose from existing Collection framework.
public int findOccurances(Collection list, String column,String item) {
int count = 0;
ObjectOne myObj;
String value="";
Iterator itr = list.iterator();
while(itr.hasNext()) {
myObj = (ObjectOne)itr.next();
if(column.equalsIgnoreCase("col1")) value = myObj.getCol1();
if(column.equalsIgnoreCase("col2")) value = myObj.getCol2();
if(value.equalsIgnoreCase(item)) {
count++;
}
}
return count;
}
Hope this would help and throw some light to improve much better.
Wrap the data elements in nodes that have count and value. On insertion, either create a new one if none exists and set the count to 1, or increment count if it's already there. The node count will then only need to be examined instead of calculated.
Related
I have a map:
Map<String, String> abc = new HashMap<>();
"key1" : "value1",
"key2" : "value2"
And an array:
String[] options= {"value1", "value2", "value3"}
I am creating this array as following (I am using following method to do something else which is not relevant to the question that I am asking here):
public String[] getOptions() {
List<String> optionsList = getOptionsFromAMethod(WebElementA);
String[] options = new String[optionsList.size()];
options = optionsList.toArray(options);
return options;
}
What is the best way to verify if String[] contains each value from Map?
I am thinking about doing this:
for (Object value : abc.values()) {
Arrays.asList(options).contains(value);
}
Explanation
Your current approach creates an ArrayList (from java.util.Arrays, not to confuse with the regular ArrayList from java.util) wrapping the given array.
You then call, for each value of the map, the ArrayList#contains method. However this method is very slow. It walks through the whole list in order to search for something.
Your current approach thus yields O(n^2) which doesn't scale very well.
Solution
We can do better by using a data-structure which is designed for a fast contains query, namely a HashSet.
So instead of putting all your values into an ArrayList we will put them into a HashSet whose contains method is fast:
boolean doesContainAll = true;
HashSet<String> valuesFromArray = new HashSet<>(Arrays.asList(options));
for (String value : abc.values()) {
if (!valuesFromArray.contains(value)) {
doesContainAll = false;
break;
}
}
// doesContainAll now is correctly set to 'true' or 'false'
The code now works in O(n) which is far better and also optimal in terms of complexity.
Of course you can optimize further to speedup by constant factors. For example you can first check the size, if options.length is greater than abc.values().size() then you can directly return with false.
JStream solution
You can also use Java 8 and Streams to simplify the above code, the result and also the procedure behind the scenes is the same:
HashSet<String> valuesFromArray = new HashSet<>(Arrays.asList(options));
boolean doesContainAll = abc.values().stream()
.allMatch(valuesFromArray::contains);
Insights of ArrayList#contains
Let's take a closer look into java.util.Arrays.ArrayList. You can find its code here.
Here is its code for the contains method:
public boolean contains(Object o) {
return indexOf(o) != -1;
}
Lets see how indexOf is implemented:
public int indexOf(Object o) {
E[] a = this.a;
if (o == null) {
for (int i = 0; i < a.length; i++)
if (a[i] == null)
return i;
} else {
for (int i = 0; i < a.length; i++)
if (o.equals(a[i]))
return i;
}
return -1;
}
So indeed, in all cases the method will traverse from left to right through the source array in order to find the object. There is no fancy method that is able to directly access the information whether the object is contained or not, it runs in O(n) and not in O(1).
Note on duplicates
If either of your data may contain duplicates and you plan to count them individually, then you will need a slightly different approach since contains will not bother for the amount of duplicates.
For this you may collect your abc.values() first into a List for example. Then, every time you checked an element, you will remove the matched element from the List.
Alternatively you can setup a HashMap<String, Integer> which counts for every element its occurrences. Then, every time you checked an element, decrease the counter by one.
You can use https://docs.oracle.com/javase/7/docs/api/java/util/List.html#containsAll(java.util.Collection)
Arrays.asList("value1", "value2", "value3").containsAll(abc.values())
I would recommend using a stream:
final List<String> optionsList = Arrays.asList(options);
abc.values().stream().allMatch(optionsList::contains);
I have an ArrayList of Items and I want to be able remove one Item from the list by entering only one Item attribute, for example its number (int ItemNumber). I also wanna do the same when I check Item quantities.
These are my equals() & contains() methods, do I need to make any changes here?
public boolean contains(T anEntry) {
boolean found = false;
for (int index = 0; !found && (index < numberOfEntries); index++) {
if (anEntry.equals(list[index]))
found = true;
}//end for
return found;
} // end contains
public boolean equals(Object object){
Item item = (Item) object;
if (itemNo == item.itemNo)
return true;
return false;
}
If you change the class Item equals() and compareTo() methods, so that they check only one object field, such as a quantity, it could result in strange behavior in other parts of your application. For example, two items with different itemNo, itemName, and itemPrice, but with the same quantities could be considered equal. Besides, you wouldn't be able to change the comparison attribute without changing the equals() code every time.
Also, creating a custom contains() method makes no sense, since it belongs to the ArrayList class, and not to Item.
If you can use Java 8, a clean way to do it is to use the new Collection's removeIf method:
Suppose you have an Item class with the num and name properties:
class Item {
final int num;
final String name;
Item(int num, String name) {
this.num = num;
this.name = name;
}
}
Given a List<Item> called items and an int variable called number, representing the number of the item you want to remove, you could simply do:
items.removeIf(item -> item.num == number);
If you are unable to use Java 8, you can achieve this by using custom comparators, binary search, and dummy objects.
You can create a custom comparator for each attribute you need to look for. The comparator for num would look like this:
class ItemNumComparator implements Comparator<Item> {
#Override
public int compare(Item a, Item b) {
return (a.num < b.num) ? -1 : ((a.num == b.num) ? 0 : 1);
}
}
Then you can use the comparator to sort and search for the desired elements in your list:
public static void main(String[] args) {
List<Item> items = new ArrayList<>();
items.add(new Item(2, "ball"));
items.add(new Item(5, "cow"));
items.add(new Item(3, "gum"));
Comparator<Item> itemNumComparator = new ItemNumComparator();
Collections.sort(items, itemNumComparator);
// Pass a dummy object containing only the relevant attribute to be searched
int index = Collections.binarySearch(items, new Item(5, ""), itemNumComparator);
Item removedItem = null;
// binarySearch will return -1 if it does not find the element.
if (index > -1) {
// This will remove the element, Item(5, "cow") in this case, from the list
removedItem = items.remove(index);
}
System.out.println(removedItem);
}
To search for another field like name, for example, you would need to create a name comparator and use it to sort and run the binary search on your list.
Note this solution has some drawbacks though. Unless you are completely sure that the list didn't change since the last sort, you must re-sort it before running the binarySearch() method. Otherwise, it may not be able to find the correct element. Sorting complexity is O(nlogn), so running it multiple times can get quite expensive depending on the size of your list.
Do you want to remove an object at a specific index? I'm not entirely sure what you mean by 'number field'. If so, jump to method: remove(int):
http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#remove%28int%29
EDIT: If you want to find/adjust a field of an object in the Array list, you can do this (piece of my own code):
public boolean studentHasISBN(ArrayList<Student> st, String s){
for(Student j : st) {
if(s.equals(j.getRentedBookISBN()))
return true;
}
return false;
}
All you have to do is iterate through the list, and search through the field that you want to find. Then use the remove(int) method.
simply use the remove function of ArrayLists in Java:
theNameOfYourArrayList.remove(ItemNumber);
to remove the element which has the index (int ItemNumber)
to check if the element with item number (int ItemNumber) exists in your ArrayList (hypothetically called theNameOfYourArrayList):
theNameOfYourArrayList.get(ItemNumber);
I'm going to assume that by 'number field' you mean that you invoked ArrayList with the Integer data type. I have a few different solutions to your problem:
ArrayLists, assuming that the ArrayList is ArrayList<Integer> numList = new ArrayList<Integer>(); you can simply write a method that will search 'numList' and delete the index that the number is. The problem is, contains and find in ArrayLists can be slow.
public void deleteNumField(int field) {
// this will stop any error if field isn't actually in numList
// and it will remove the first index of field in the ArrayList
if(numList.contains(field)) numList.remove(numList.find(field));
}
HashSets, HashSets are a handy data type that is like an ArrayList, except, its data is its 'index' (sortof). I won't go in depth about how they work, but I will say that searching in them is considered O(1). This will make your deletion really easy, and fast. Note: the HashSet assumes there are no duplicate numbers, if there are use a HashMap.
HashSet<Integer> numList = new HashSet<Integer>();
public void deleteNumField(int field) {
// this will stop errors from attempting to remove a
// non-existant element, and remove it if it exists.
if(numList.contains(field)) numList.remove(field);
}
For more information on HashMaps, HashSets and ArrayLists, see:
http://docs.oracle.com/javase/8/docs/api/
What are the the best methods to get values that occur more than once in a large list of words without slowing my run time?. My file contains 1xx,xxx words and I put them into a linked list. Now, I want to get only the words that occur more than once out of that list.
For example, if a list contains:
....This is is is just a test test....
I want to get is and test and put them into another list using an iterator.
I don't know if my code is right, and I think that this is not the best solution to approach for this problem.
for(int i = 0; i < word.size(); i++) {
Word s = word.get(i);
Word s1 = word.get(i+1);
if(s.equals(s1)) {
newWord.add(s);
}
}
Put them all into HashSet instead of list and check the return value of add() method.
HashSet<Word> wordSet = new HashSet<>();
for(int i = 0; i < word.size(); i++) {
if(!wordSet.add(word.get(i)){
//Found duplicate
}
}
Note that you can also do it during/instead of creation of the list of the words.
Build a hashmap with the word as key and it count as value.
for(each word in list)
{
count = 1;
if(map.contains(word))
{
count = map.get(word);
}
else
count = 1;
map.put(word,count);
}
Then iterate over the hashmap and check if values is 1, and add the word to your list.
If you can sort the list, then finding duplicates is quick and easy.
The method below (generateID())it generate a random ids, And when i store students in the HashMap i want to check if the generated id is not exist in the hashMap value and if its exists I want to generate a new id and then store it, The problem with the method store sometimes it does not store all the student because some student might have the same id and this is not allowed, So what is the best why to check that all ids are uniqe and if there is duplication the method generateid will be called again util all the ids are uniqe and then it will store it, I want to ensure that the ids values produced by generateId() are all different
private String generateId(String perfix, int numberaOfDigits)
{
for(int i=0;i<numberaOfDigits;i++)
{
perfix += randomGenerator.nextInt(9)+ 1;
}
return perfix;
}
public void store(Student student)
{
int index = 0;
studentMap.setId(generateId("AB-",1));
while(index <= studentMap.size())
{
for(Student stu : studentMap.values() )
{
if(student.getStduentID().equals(stu.getStduentID()))
{
student.setId(generateId("AB-",1));
}
}
index++;
}
}
studentMap.put(student.getStduentID(),student);
}
you can use the containsKey() method to check if an ID is already in use as key
Use an UUID. Or a sequence as already answered
If that's actually a Map implementation, you should be able to use .containsKey(). The problem is that, depending on how well written your ID generator is, this can cause significant performance issues over time. Say you have a 6 digit ID, and in a few years 80000 students have passed through the system. How many guesses will it need before it finds one of the remaining 20000 available keys?
You can get from the map with the generated Id, if it returns null, then it doesn't exist
yet.
Map<Long, Object> myMap = new HashMap<Long, Object>();
Long id = generateRandomId()
Object value = getMyObjectValue();
while(myMap.get(id) != null){
id = generateRandomId();
}
myMap.put(id, value);
I would eliminate the generateId() method altogether, and simply do this:
private int id;
then:
student.setId(id++);
I suggest to try following implementation to get unique random number each time.
Add items to the list .
Use Collections.shuffle(list); to shuffle the list .
Iterate over list and get random number each time from the given range. (For below case range is from 0 to numberOfStudent-1).
int numberOfStudent = 10;
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < numberOfStudent; i++)
list.add(i);
Collections.shuffle(list);
I want to get specific combination of permutation of string like alphabet. To understand me, I'll show you the code that I using:
public class PermutationExample {
public static List<String> getPermutation(String input) {
List<String> collection = null;
if (input.length() == 1) {
collection = new ArrayList<String>();
collection.add(input);
return collection;
} else {
collection = getPermutation(input.substring(1));
Character first = input.charAt(0);
List<String> result = new ArrayList<String>();
for (String str : collection) {
for (int i = 0; i < str.length(); i++) {
String item = str.substring(0, i) + first
+ str.substring(i);
result.add(item);
}
String item = str.concat(first.toString());
result.add(item);
}
return result;
}
}
public static void main(String[] args) {
System.out.println(PermutationExample.getPermutation("ABCD"));
}
}
This code works well and i can get every combination, I can take it from the list, if I need 5-th element, I can receive it. But if the string is the alphabet ... , didn't works, it's too big. What I have to do, to get the specific element like 1221-th from all 26! combinations ?
I solved a similar problem a while ago, only in python.
If what you need is simply the n-th permutation, then you can do a lot better then generating every permutation and returning the n-th, if you try to think about generating only the permutation you need.
You can do this "simply" by figuring out what should be the element in front for the number of permutations you want, and then what should be the remaining of the elements recursively.
Assume a collection of values [0, ... ,X], for any values such that col[n] < col[n+1]
For N elements, there are N! possible permutations, the case when the collection will be perfectly reversed.
We will see the change in the head of the collection after each (N-1)! permutations, so if n < (N-1)!, the head is the head. You then have a remaining number of permutations, and you can apply the same logic recursively.
Does this help? I know it's fairly high level and you'll have to think a bit about it, but maybe it'll get you on the right track.