I need an advise on the best approach to complete this task in my android app:
I am working on an android app and got stuck on how to calculate the diagnosis of the patient.
The user (doctor) will perform physical tests on the patient
The user records the value of each physical test <= this data is stored in a shared pref object
i.e- when the user performs an empty can test (physical test), the user will record if the test is positive (1) or negative (0) <= Boolean value (for simplicity, I am using only 4 tests)
The application is supposed to compare the patient findings to the conditions that I want to just hard code in my app (for simplicity, I am using only 8 conditions to compare) then display the condition that the patient would most likely have
--> I am storing the physical test, performed on the patient, results in a shared preference object but do not know how to go from there to come up with the diagnosis (I am looking for a simple approach to make this work)
*** I saved the values from my shared preference object into one dimensional array as below:
// User SharedPreferences to save the value per special id
SharedPreferences sharedPref = getSharedPreferences("STData", Context.MODE_PRIVATE);
Map<String, String> map = (Map<String, String>) sharedPref.getAll();
int[] PTFindings = new int[map.size()];
int index = 0;
if(!map.isEmpty()){
Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry entry = (Map.Entry)iterator.next();
PTFindings[index] = (int) entry.getValue();
}
}
**** How should I hard code few conditions to proceed? -> assuming the results of the physical tests of those conditions (positive (1) or negative (0)) do not change
*** I need to compare their values to the one I saved from shared preference then display the most likely diagnosis
Any suggestion would be greatly appreciated
As far as I could understando from your question, you just need a cascading condition.
if(boolean1){
if(boolean2){
//something boolean2 related
} else {
if(boolean3){
etc...
}
}
} else {
//something boolean1 related
}
Related
I have two hashmaps (resources and neededResources).
Goal is to reduce the amount of resources hashmap, but that can only happen if it has enough of both resource.
// String = name of resources available
// Integer = amount of resources available
Map<String, Integer> resources = new HashMap<>();
resources.put("gold", 10);
resources.put("silver", 10);
// String = name of resource needed
// Integer = amount of resource needed
Map<String, Integer> neededResources = new HashMap<>();
neededResources.put("gold", 2);
neededResources.put("silver", 3);
In this sample case, it would take resources 3 times since on 4th try there wouldn't be enough silver, gold value doesn't change as well.
I'm a novice at Java. So far I've tried iterating through both of them but it becomes hard to read and my attempts have looked way too difficult for this task.
I think this might be what you are after. The code can be inserted after your setup code.
Find the number of possible expenditures:
int n = resources.entrySet().stream().mapToInt(entry -> entry.getValue()/neededResources.getOrDefault(entry.getKey(), 0)).min().getAsInt();
System.out.println(n);
Prints 3
Spend it:
resources.replaceAll((k,v) -> v-n*neededResources.getOrDefault(k,0));
System.out.println(resources);
Prints {gold=4, silver=1}
Take the value from your resources map, substract the value from neededResources and check if it is >=0. This tells you that there were at least as many resources available as needed. If resources were available, update the value. Otherwise dont.
Create a method wrapper in your resources class
public boolean hasResources(String... pResources){
for(String resourceKey : pResources){
int newValue = resources.get(pResourceKey) - neededResources.get(pResourceKey);
if(newValue < 0){
return false;
}
}
return true;
}
public void takeResources(String... pResources){
for(String resourceKey : pResources){
int newValue = resources.get(pResourceKey) - neededResources.get(pResourceKey);
resources.put(resourceKey, newValue);
}
}
The key to this problem is that we don't want to modify the resources Map unless we are absolutely sure that it contains all of the resourcesNeeded. Once you learn about Streams in Java, this problem should simplify.
First, we want to check if the resources Map contains all of the keys in the resourcesNeeded Map, which may or may not already be given information which you haven't mentioned.
resources.keySet().containsAll(neededResources.keySet());
If that condition is false, then we know that there are needed resources that are not available. Otherwise, we can now check if every value in resources is greater than or equal to the value in resourcesNeeded for its respective key:
resources.entrySet()
.stream()
.allMatch(entry -> entry.getValue() >= resourcesNeeded.get(entry.getKey()));
If that condition is false, then more resources are needed then are currently available. Otherwise, we can now modify resources, essentially subtracting each respective value in resourcesNeeded:
resources.replaceAll((k, v) -> v - resourcesNeeded.getOrDefault(k, 0)));
The last two statements can be placed inside of a loop to ensure that the minimum amount of resources remain.
Ive been searching SO about this question and most only have the problem with two arrays comparing by have a nested loop. My problem is quite the same but on a bigger scale. Suppose I have a 100 or thousand user on my app, and each user has the list of item it wants.
Something like this
User1 = {apple,orange,guava,melon,durian}
User2 = {apple, melon,banana,lemon,mango}
User3 = {orange,carrots,guava,melon,tomato}
User4 = {mango,carrots,tomato,apple,durian}
.
.
Nuser = ...
I wanted to see how many apples or oranges was listed from all the users array. So I am basically comparing but on a bigger scale. The data isn't static as well, A user can input an unknown fruit from the developers knowledge but on the users knowledge they can put it there so there can be multiple users that can put this unknown fruit and yet the system can still figure out how many is this unknown item was listed. Keep in mind this is a dynamic one. User can reach for example a 100 users depending how popular an app would be. I can't afford to do nested loop here.
PS this is not the exact problem but it is the simplest scenario I can think of to explain my problem.
PS: just to clarify, I dont intend to use 3rd party lib as well like guava. I am having a problem on proguard with it.
Edit
Just read that Original poster cannot use Java 8, which is a pity, because this would realy make it very easy!
Java 7 solution
final Map<String, Integer> occurencesByFruit = new HashMap<>();
for (User user : users) {
String[] fruits = user.getFruits();
for (String fruit : fruits) {
final Integer currentCount = occurencesByFruit.get(fruit);
if (currentCount == null) {
occurencesByFruit.put(fruit, 1);
} else {
occurencesByFruit.put(fruit, currentCount + 1);
}
}
}
Java 8 solution
I'd stream the users, flatMap() to the actual fruit elements, and then use Collectors.groupingBy() with a downstream collector Collectors.counting().
This will give you a Map where the keys are the fruits, and the values are the occurrences of each fruit throughout all your users.
List<User> users = Arrays.asList(/* ... */);
final Map<String, Long> occurencesByFruit = users.stream()
.map(User::getFruits)
.flatMap(Arrays::stream)
.collect(Collectors.groupingBy(f -> f, Collectors.counting()));
Seems it is a good possibility to use HashMap<Item, Integer> fruits. You could iterate over all Users (you would need to store all Users in some kind of list, such as ArrayList<User> users) and check the list of items chosen by each User (I suppose User should have a field ArrayList<Item> items in its body to store items). You could achieve it with something like that:
for (User user : users) { // for each User from users list
for (Item item : user.items) { // check each item chosen by this user
if (fruits.containsKey(item) { // if the fruit is already present in the items HashMap increment the amount of items
int previousNumberOfItems = fruits.get(item);
fruits.put(item, ++previousNumberOfItems);
else { // otherwise put the first occurrency of this item
fruits.put(item, 1);
}
}
}
I would either create an ArrayList containing a HashMap with strings and ints or use two ArrayLists (one of type String and one of type Integer). Then you can iterate over every entry in each of the user arrays (this is only a simple nested loop). For every entry in the current user array you check if there is already the same entry in the ArrayList you created additionally. If so, you increment the respective int. If not, you add a string and an int. In the end, you have the number of occurrences of all the fruit strings in the added ArrayLists, which is, if I understood you correctly, just what you wanted.
I want to create one report that you select product and storeName and returns all the sales per date (within a range).
The db view that helped me with other reports looks like this:
product - store_name - date
So far my approach is to return all records from the db in a list and then I do the following:
public void salesReport(String product, String store, String date){
List<RecordSalesInfo> salesResults = salesDao.getSales();
Map<String, Integer> mapper = new HashMap();
//calculation
for (RecordSalesInfo record : salesResults) {
StringBuilder key = new StringBuilder();
key.append(record.getProduct()).append(":")
.append(record.getStoreName()).append(":")
.append(record.getWageredDate()).append(":");
if (mapper.containsKey(key.toString())) {
Integer get = mapper.get(key.toString());
get++;
mapper.put(key.toString(), get);
} else {
mapper.put(key.toString(), 1);
}
}
for (String key : mapper.keySet()) {
if(key.toString.equals("Pen:London:13June2016"){
System.out.println("sales:" + mapper.get(key.toString);
}
}
}
the query in the salesDao(saving as "RecordSalesInfo") is:
SELECT
rs.product AS product,
rs.store_name AS store,
rs.date AS date,
rs.product_id AS productId
FROM sales rs
ORDER BY rs.product,rs.store_name,rs.date
The reason I didn't query "Count(blabla) where product='a' and store_name='b' and date='c' " is because the user changes the input using a jSlider very often (input=product,store,date), that means too many queries. So I thought it is better to take all the results from db and then display what the user needs.
A) Is there a better way to do this?
B) In the next phase the user will enter only the product and the store and I have to return the list of the sales by date, looking like this:
Pen - London (manual input)
12June2016 100
15June2016 30
19July2016 67
With what I have done so far, I can't get only the dates that I have sales, and I have to "search" from the hashMap for all dates(specific range). I think as a solution to change the key to "product:storeName" one the existing map and have as a value another map where the String will be the date and the Integer the amount of sales.
Again is there a better way on doing that?
What I would do is that I will not hold/keep a map, rather I will fetch the results as the query changes based on the JSlider etc.
You can do one thing that when a query is sent until its results are available you can disable your Jslider and show a spinner that notifies the user that processing is going on.
Once the result is available, enable the slider and hide the spinner.
To have all the data in the map does not seem a good idea. It will be a disconnected state of data.
I am developing an app that generates passwords randomly. I am adding a "save" feature so that the user can save their passwords in SharedPreferences. (which is not what you are supposed to do with your passwords)
I have an activity called PasswordActivity and in that activity I display the saved passwords.
This is how I save a password: I prompt the user to enter a name/key thingy for the password so that he/she can identify it later. And then I save the key and the password in the SharedPreferences using the following method in a utility class:
public static int savePassword (Context c, String passwordKey, String passwordValue) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences (c);
Set<String> keys = prefs.getStringSet (PASSWORD_KEYS, new HashSet<String> ());
Set<String> values = prefs.getStringSet (PASSWORD_VALUES, new HashSet<String> ());
SharedPreferences.Editor editor = prefs.edit ();
boolean duplicateKey = !keys.add (passwordKey);
boolean duplicateValue = !values.add (passwordValue);
if (duplicateKey)
return KEY_DUPLICATE;
if (duplicateValue)
return VALUE_DUPLICATE;
editor.putStringSet (PASSWORD_KEYS, keys).
putStringSet (PASSWORD_VALUES, values).apply ();
return SUCCESS;
}
And I wrote another method to get the passwords and their names. The method returns a HashMap<String, String> as you might have guessed.
public static HashMap<String, String> getPasswords (Context c) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences (c);
Set<String> keys = prefs.getStringSet (PASSWORD_KEYS, new HashSet<String> ());
Set<String> values = prefs.getStringSet (PASSWORD_VALUES, new HashSet<String> ());
ArrayList<String> keysList = new ArrayList<> ();
ArrayList<String> valuesList = new ArrayList<> ();
for (String key : keys) {
keysList.add (key);
}
for (String value : values) {
valuesList.add (value);
}
HashMap<String, String> map = new HashMap<> ();
for (int i = 0 ; i < keys.size () ; i++) {
map.put (keysList.get (i), valuesList.get (i));
}
return map;
}
I admit that the code is pretty messy. I first get the things in the two sets and turn them into ArrayLists and add the stuff in the array list to the map and return.
Phew! That was a lot of work!
Now when the user generates a password and saves it, the two sets contain the right things: (These are fake data)
keys:
key1
values:
value1
That's all good. But when I generate another password and save it, the two sets become messy:
keys:
key1
key2
values:
value2
value1
Now when I call the getPasswords method, it will return
{key1, value2}, {key2, value1}
which is incorrect. After looking at the docs, I found out that:
It makes no guarantees as to the iteration order of the set; in particular, it does not guarantee that the order will remain constant over time.
which I guess is the reason that makes the incorrect results.
So I was wondering is there an alternative way to store these passwords and their names?
As you're storing multiple names & passwords, i would suggest a local SQLite database. SharedPreferences are meant for single values, not sets of values.
If you can't be bothered setting up the entire SQLiteOpenHelper and all that raw SQL code, you could take a look at some ORM helpers such as SugarOrm (i currently use this, its EXTREMELY easy to set up and use)
I would recommend a database, such as SQLCipher for Android, so the user can provide a master passphrase for the app, and all the data is stored encrypted on the device.
But, let's pretend that, in order to successfully repel an alien invasion and prevent the wholesale slaughter of countless humans, you have to implement this using SharedPreferences. After that, you will need to fly with a wise-cracking companion in a commandeered alien spacecraft and successfully upload your app into the computer systems of one of the alien mother ships (which, fortunately, happen to be running Android, as Android has remarkable market share across the galaxy).
Either:
Have each key and value be separate entries in the SharedPreferences. After all, SharedPreferences is a key-value store. Use a dedicated preference file for your keys and values (so as not to collide with anything else you might want to store), then you know that all the keys are ones from the user.
Marshal the HashMap into JSON or XML or something and save that as a string, unmarshalling it as needed.
I need to be able to sort multiple intermediate result sets and enter them to a file in sorted order. Sort is based on a single column/key value. Each result set record will be list of values (like a record in a table)
The intermediate result sets are got by querying entirely different databases.
The intermediate result sets are already sorted based on some key(or column). They need to be combined and sorted again on the same key(or column) before writing it to a file.
Since these result sets can be massive(order of MBs) this cannot be done in memory.
My Solution broadly :
To use a hash and a random access file . Since the result sets are already sorted, when retrieving the result sets , I will store the sorted column values as keys in a hashmap.The value in the hashmap will be a address in the random access file where every record associated with that column value will be stored.
Any ideas ?
Have a pointer into every set, initially pointing to the first entry
Then choose the next result from the set, that offers the lowest entry
Write this entry to the file and increment the corresponding pointer
This approach has basically no overhead and time is O(n). (it's Merge-Sort, btw)
Edit
To clarify: It's the merge part of merge sort.
If you've got 2 pre-sorted result sets, you should be able to iterate them concurrently while writing the output file. You just need to compare the current row in each set:
Simple example (not ready for copy-and-paste use!):
ResultSet a,b;
//fetch a and b
a.first();
b.first();
while (!a.isAfterLast() || !b.isAfterLast()) {
Integer valueA = null;
Integer valueB = null;
if (a.isAfterLast()) {
writeToFile(b);
b.next();
}
else if (b.isAfterLast()) {
writeToFile(a);
a.next();
} else {
int valueA = a.getInt("SORT_PROPERTY");
int valueB = b.getInt("SORT_PROPERTY");
if (valueA < valueB) {
writeToFile(a);
a.next();
} else {
writeToFile(b);
b.next();
}
}
}
Sounds like you are looking for an implementation of the Balance Line algorithm.