I have a M/R function, and I get NaN as a value for some of the results. I dont have any experience with JS. Im escaping JS using Java Drivers.
String map = "function(){" + " emit({"
+ "country: this.info.location.country, "
+ "industry: this.info.industry}, {count : 1}); }";
String reduce = "function(key, values){var count = 0.0;"
+ "values.forEach(function(v){ count += v['count'];});"
+ "return count;}";
MapReduceOutput output = collection.mapReduce(map, reduce, null,
new BasicDBObject("lid", "foo"));
An example ti help clear things:
{"_id":{"country":"gb", "industry":"foo"}, "value":NaN}
Thanks a lot.
I see you have solved the problem, but here's why the problem occurred.
MongoDB may rerun your reduce function on the results of previous reduce passes. This is called a re-reduce.
If a re-reduce occurred in your original scenario, you could end up with values like this:
[
{ count: 1 },
{ count: 1 },
4
{ count: 1 },
{ count: 1 },
{ count: 1 },
3
{ count: 1 },
]
All the { count: 1 } values are emitted by your map function. The numbers 4 and 3 are the results of previous reduce calls. Your reduce function will then access the count property of a number:
count += 4["count"];
A number doesn't have a count property, so it will return undefined. Adding undefined to a number will result in NaN.
To avoid this kind of hard-to-debug problem, you need to make sure your reduce function is idempotent. The easiest way to accomplish this is to return what you emit; the value you return in the reduce function should be of the same format as the values you emit in the map function.
I solved it. Changed the loop, as anirvan said. But still I got a NaN. So i changed the return statement as such:
for(var i in values) { count += values[i].count; } return {count: count}; }
That did the trick. Ill need an extra line to parse it, but IDC.
Considering only the JS part, i'm not sure whether the following part is valid -
values.forEach(function(v){ count += v['count'];});
try this instead -
var v;
for (v in values)
{
....
}
hope that helps!
Related
Similar to the bellow question, however I'm expanding with more specific inquiries. Also, this is setting aside opinions on whether or not to use the ternary or normal styling of if/else's.
Applying increment using ternary operator in Java
So in theory, the following snippet:
if (text.equals("foo"))
data++;
else if (text.equals("bar"))
data--;
should look like this using the ternary operators:
data = text.equals("foo") ? data++ : text.equals("bar") ? data-- : data;
However, in my android (Java) application, android studio showed me a warning:
The value changed at 'data++' is never used
Like-wise, when I ran this in my application, the data variable stayed the same. However, when I changed the line of code to this:
data = text.equals("foo") ? data + 1 : text.equals("bar") ? data - 1 : data;
It worked.
So, this makes me wonder if the ++/-- operator is allowed within this context?
Does anyone have any input on this?
The post-increment (data++) and post-decrement (data--) operators return the value of the variable prior to its increment/decrement, so assigning it back to the variable cancels the increment/decrement.
You can use pre-increment and pre-decrement instead (or data + 1 and data - 1 as you did):
data = text.equals("foo") ? ++data : text.equals("bar") ? --data : data;
because it only check the condition and return the answer as condition is true or false it cannot work with increment decrement operator if you really want to apply increment decrement in that you can apply loop in and in that condition you place on count operation if count increment then increment operation is performed otherwise it performed decrement operation
In ternary operators, if you break it down, it will be
if(text.equals("foo")){
data = data++;
} else if(text.equals("bar")){
data = data--;
} else {
data = data;
}
And you are using post incremental and decremental operator on variable, which is assigned to itself. This can be break as
data = data++; This can be seen as
int temp = data;
data = data +1;
data = temp;
And same with the post incremental case. So in every case data value will not change.
With example
data = 10;
int temp = data;// temp = 10;
data = data + 1; // data = 11;
data = temp; // data = 10;
you can also remove the assignment from the statement and it will works fine. i.e.
text.equals("foo") ? data++ : text.equals("bar") ? data-- : data;
I'm currently working on a project where I need to work with a .csv file that is around 3 million lines long and different .xlsx files that range in size between 10 lines long and over 1000 lines long. I'm trying to find commonalities between different cells in my .xlsx file and my .csv file.
To do this. I've read in my .csv file and .xslx file and stored both in ArrayLists.
I have what I want to work, working however the method I'm using is O(n^3) using a 3 nested for loop do search between each.
//This is our .xlsx file stored in an ArrayList
for(int i = 1; i<finalKnowledgeGraph.size(); i+=3) {
//loop through our knowledgeGraph again
for(int j = 1; j<finalKnowledgeGraph.size(); j+=3) {
//loop through .csv file which is stored in an ArrayList
for(int k=1; k<storeAsserions.size(); k++) {
if(finalKnowledgeGraph.get(i).equals(storeAsserions.get(k)) && finalKnowledgeGraph.get(j+1).equals(storeAsserions.get(k+1))){
System.out.println("Do Something");
} else if(finalKnowledgeGraph.get(i+1).equals(storeAsserions.get(k)) && finalKnowledgeGraph.get(j).equals(storeAsserions.get(k+1))) {
System.out.println("Do something else");
}
}
}
}
At the moment in my actual code, my System.out.println("Do something") is just writing specific parts of each file to a new .csv file.
Now, with what I'm doing out of the way my problem is optimization. Obviously if im running a 3 nested for loop over millions of inputs, it won't be finished running in my life time so I'm wondering what ways I can optimize the code.
One of my friends suggested storing the files in memory and so read/writes will be several times quicker. Another friend suggested storing the files in hashtables instead of ArrayLists to help speed up the process but since I'm essentially searching EVERY element in said hashtable I don't see how that's going to speed up the process. It just seems like it's going to transfer the searching from one data structure to another. However I said i'd also post the question here and see if people had any tips/suggestions on how I'd go about optimizing this code. Thanks
Note: I have literally no knowledge of optimization etc. myself and I found other questions on S/O too specific for my knowledge on the field so if the question seems like a duplicate, I've probably seen the question you're talking about already and couldn't understand the content
Edit: Everything stored in both ArrayLists is verb:noun:noun pairs where I'm trying to compare nouns between each ArrayList. Since I'm not concerned with verbs, I start searching at index 1. (Just for some context)
One possible solution would be using a database, which -- given a proper index -- could do the search pretty fast. Assuming the data fit in memory, you can be even faster.
The principle
For problems like
for (X x : xList) {
for (Y y : yList) {
if (x.someAttr() == y.someAttr()) doSomething(x, y);
}
}
you simply partition one list into buckets according to the attribute like
Map<A, List<Y>> yBuckets = new HashMap<>();
yList.forEach(y -> yBuckets.compute(y.someAttr(), (k, v) ->
(v==null ? new ArrayList<>() : v).add(y));
Now, you iterate the other list and only look at the elements in the proper bucket like
for (X x : xList) {
List<Y> smallList = yBucket.get(x.someAttr());
if (smallList != null) {
for (Y y : smallList) {
if (x.someAttr() == y.someAttr()) doSomething(x, y);
}
}
}
The comparison can be actually left out, as it's always true, but that's not the point. The speed comes from eliminating to looking at cases when equals would return false.
The complexity gets reduced from quadratic to linear plus the number of calls to doSomething.
Your case
Your data structure obviously does not fit. You're flattening your triplets into one list and this is wrong. You surely can work around it somehow, but creating a class Triplet {String verb, noun1, noun2} makes everything simpler. For storeAsserions, it looks like you're working with pairs. They seem to overlap, but that may be a typo, anyway it doesn't matter. Let's use Triplets and Pairs.
Let me also rename your lists, so that the code fits better in this tiny window:
for (Triplet x : fList) {
for (Triplet y : fList) {
for (Pair z : sList) {
if (x.noun1.equals(z.noun1) && y.noun2.equals(z.noun2)) {
doSomething();
} else if (x.noun2.equals(z.noun1) && y.noun1.equals(z.noun2)) {
doSomethingElse();
}
}
}
}
Now, we need some loops over buckets, so that at least one of the equals tests is always true, so that we save us dealing with non-matching data. Let's concentrate on the first condition
x.noun1.equals(z.noun1) && y.noun2.equals(z.noun2)
I suggest a loop like
for (Pair z : sList) {
for (Triplet x : smallListOfTripletsHavingNoun1SameAsZ) {
for (Triplet y : smallListOfTripletsHavingNoun2SameAsZ) {
doSomething();
}
}
}
where the small lists get computes like in the first section.
No non-matching entries get ever compared, so the complexity gets reduced from cubic to the number of matches (= to the number if lines you code would print).
Addendum -yBuckets
Let's assume xList looks like
[
{id: 1, someAttr: "a"},
{id: 2, someAttr: "a"},
{id: 3, someAttr: "b"},
]
Then yBuckets should be
{
"a": [
{id: 1, someAttr: "a"},
{id: 2, someAttr: "a"},
],
:b": [
{id: 3, someAttr: "b"},
],
}
One simple way, how to create such a Map is
yList.forEach(y -> yBuckets.compute(y.someAttr(), (k, v) ->
(v==null ? new ArrayList<>() : v).add(y));
In plaintext:
For each y from yList,
get a corresponding map entry in the form of (k, v),
when v is null, then create a new List
otherwise work with the List v
In any case, add y to it
and store it back to the Map (which is a no-op unless when a new List was created in the third step).
I'm trying to make some instructions when there will be appropriate minimum integer value. For example: when variable "round_min" = 10 -> there are some instructions. When "round_min" = 100 -> there is another instruction.
I try to implement function which finds minimum value in HashMap.
For example: I have two elements in HashMap. And there is finding minimum value, and it's displaying in TextView properly.
But when I want to use this variable "round_min" to another function there are displaying all values in hashmap. I want to have always the minimum.
Below I present code:
int round_min;
// nearestDistances is a hashmap where I put distances
Map.Entry<String, Float> nearestMarker = null;
for (Map.Entry<String, Float> entry : nearestDistances.entrySet()) {
if (nearestMarker == null || nearestMarker.getValue() > entry.getValue()) {
nearestMarker = entry;
round_min = Math.round(nearestMarker.getValue());
Log.e(" MIN ", round_min + "");
// it displays in log.e all values
// this function see all values, not only minimum
DisplayMinimumValue(getApplicationContext(), round_min);
Log.e(" ROUND MIN ", round_min + "");
tvDistanceToNearest.setText(String.valueOf(round_min)); // there is displaying only minimum value
}
}
Could someone help me to find the problem and how to figure out with it?
move all the lines
// this function see all values, not only minimum
DisplayMinimumValue(getApplicationContext(), round_min);
Log.e(" ROUND MIN ", round_min + "");
tvDistanceToNearest.setText(String.valueOf(round_min)); // there is displaying only minimum value
at the end, after second } so that you are outside the loop
Since i can't comment yet... i'm unsure what your question is. I see that you are updating your round_min variable if you encounter a smaller value in the map. I also see that you have some methods that use that variable inside your iteration. What part of the program is not acting like you want it to?
Ok I'm sure I'm doing something wrong here.
result = []
for (aMp in arMap) {
println("0 " + result)
println("1 " + aMp)
println("2 " + delegate.findSingleMap(aMp))
result.addAll(delegate.findSingleMap(aMp))
println "3 " + result
}
return result
The println result are the following: (I have 2 element in arMap, so it print the four value 2 times)
0 []
1 [ID:XXX, Type:4]
2 [[First:21/Nov/2013, Type:4, error code:SXR07, ID:XXX, Test ID:5]]
3 [[First:21/Nov/2013, Type:4, error code:SXR07, ID:XXX, Test ID:5]]
0 [[First:21/Nov/2013, Type:4, error code:SXR07, ID:XXX, Test ID:5]]
1 [ID:YYY, Type:4]
2 [[First:12/Oct/2012, Type:4, error code:SXR07, ID:YYY, Test ID:6]]
3 [[First:12/Oct/2012, Type:4, error code:SXR07, ID:YYY, Test ID:6]]
As you can see the findSingleMap function work properly, but the second time I use the AddAll, my result array loose the value XXX.
What am I doing wrong?
As stated by the OP int the comments the method findSingleMap modifies the (global) result variable.
for (aEl in map) {
result = result.findAll { it[aEl.key] == aEl.value }
}
return result
Not writing def in front a variable declares it (in simple scripts) global, which might result in strange behaviour like this. So don't do it, unless you have to codegolf.
I have a puzzle that I solved. I will try to briefly describe it and then ask question.
Map phone numbers to text. For example:
101 -> 101, but 501 -> J01, K01, L01 (AFAIK).
We get 9digit number and need to produce all combination, even those that are not grammaticaly correct.
I created a program that basically grows like a tree. When a number that is not 0 or 1 is found we create a new branch with already translated text + one of possible letters + rest of number.
I solved it by creating a new thread every time new translateable digit is encountered.
Do you think it is a bad practice? Can it be solved better?
Thank you.
Creating a thread for each possibility seems like overkill, what you really want is recursion. Try this:
String [] lookup = { "0", "1", "ABC", "DEF", "GHI", "JKL", "MNO", "PQRS", "TUV", "WXYZ" };
List<String> results = new ArrayList<String>();
void translatePhone(String phoneNumber, int position) {
int index = Integer.parseInt(phoneNumber.substring(position, position + 1));
for (int i = 0; i < lookup[index].length; i++) {
String xlated = phoneNumber.substring(0, position) + lookup[index].charAt(i) + phoneNumber.substring(position + 1);
if (position + 1 == phoneNumber.length) {
results.add(xlated);
} else {
translatePhone(xlated, position + 1);
}
}
}
Call translatePhone(phoneString, 0) to start it off. Once that returns results should have all your results.