Is there a way in Scalding Type Safe API to mapWithValue with two or more ValuePipes? - scalding

Using Scalding, Type Safe API, this code works, where dictForKeys and dictForValues are both ValuePipe[Map[String,String]]:
SomeKeyValueTypedPipe
.mapWithValue(dictForKeys) { case ((key, value), dictForKeys) =>
(dictForKeys.get.getOrElse(key, key), value) }
.mapWithValue(dictForValues) { case ((key, value), dictForValues) =>
(key, dictForValues.get.getOrElse(value, value)) }
I was just wondering whether there's a more compact way of writing this, i.e. use only 1 mapWithValue step with 2 separate ValuePipes.

You could create a ValuePipe of a tuple of Maps, like ValuePipe[(Map[String, String], Map[String, String])], and then use it like so:
SomeKeyValueTypedPipe
.mapWithValue(dict) { case ((key, value), (dictForKeys, dictForValues)) =>
(dictForKeys.get.getOrElse(key, key), dictForValues.get.getOrElse(value, value)) }

Related

How to delete items from an array in Vue

I have a function called updateAnswer with multiple dynamic parameters.
updateAnswer(key, answer, array = false) {
if (array) {
if(this.answers.contains.find(element => element === answer)) {
//Delete item from array if already element already exists in this.answers.contains array.
} else {
Vue.set(this.answers, key, [...this.answers.contains, answer]);
}
} else {
Vue.set(this.answers, key, answer);
}
},
I'd like to know how delete an item in the array if the value already exists in the array.
You can use method called splice:
Just reference on your array and set values in the brackets the first is referenced on the position, the second is how many datas you want to splice/delete.
The function looks like this:
this.array.splice(value, value)
Lets see on an example - you have array food= [apple, banana, strawberry] than I'm using this.food.splice(1,1)..
my array looks now like this food = [apple, strawberry] - first value in my brackets are the position, the second one is the amount of "numbers" you want to delete.
Hopefully this helps you out!
I suppose each value in this.answers.contains is unique?
Anyways, if you just want to delete the item if already exists, I suggest filter(). It should look like below:
if(this.answers.contains.find(element => element === answer)) {
this.answers.contains = this.answers.contains.filter(c => c !== answer)
}
Also, the if condition if(this.answers.contains.find(element => element === answer)) could also be replaced by if(this.answers.contains.includes(answer))
Hope that could help you.

Am I overwriting computed property filter in Vue?

I am trying to create a reactive filter for an array in Vue. My starting array comes from an API call which returns this.features (geojson features). I am filtering on a nested array. This works -- but when I enter a search term and then backspace back out to an empty string, and enter another string, I am not filtering the original array but appear to be filtering the already-filtered array. How could I filter again on the original array from the API call?
computed property:
filteredFeatures() {
if (this.searchTerm == '') {
return this.features
}
// filter on nested array
let filtered = this.features.filter(feature => {
feature.properties.site_observations = feature.properties.site_observations.filter(
el => JSON.stringify(el).match(this.searchTerm, 'i')
)
return feature.properties.site_observations.length > 0
})
return filtered
}
I have looked at Vue filtering objects property but I cannot make that code work (it uses Object.assign()). Thanks for any ideas.
Your computed property is mutating feature.properties.site_observations, that's a nono. Computed properties should be read only.
filteredFeatures() {
if (this.searchTerm == '') {
return this.features
}
// filter on nested array
let filtered = this.features.filter(feature => {
const site_observations = feature.properties.site_observations.filter(
el => JSON.stringify(el).match(this.searchTerm, 'i')
)
return site_observations.length > 0
})
return filtered
}
It seems here is your problem:
feature.properties.site_observations = feature.properties.site_observations.filter(
el => JSON.stringify(el).match(this.searchTerm, 'i')
)
Because this code filter feature and alter the proprieties of feature.properties.site_observations. Then, in the next read the value is alter. We say that your function it is not pure, because it alter the state of feature.
So, what you should do is:
let anotherVariable = feature.properties.site_observations.filter(
el => JSON.stringify(el).match(this.searchTerm, 'i')
)
Therefore, on a function, avoid alter state of objects, this lead to bugs.
On further checking, the above answer returns all site_observations, not just the ones that match the search. A much better solution is the following, using map to avoid overwriting the data, and the object spread operator to perform an object assign, and drilling down through the nested objects as follows:
filteredFeatures() {
return this.features
.map(feature => ({
...feature,
properties: {
site_observations: feature.properties.site_observations.filter(
element => {
return JSON.stringify(element).match(new RegExp(this.search, 'i'))
}
)
}
}))
.filter(feature => feature.properties.site_observations.length)
}

How to get result using better algorithm?

We have the list like below
List:
(("herry","0,1,2"),("herry","1,3"),("herry","3,6"),("herry","4"),("John","5"))
As the number in the string may be referred by different elements, the expected result is:
("herry","0,1,2,3,6"), ("herry","4"), ("John","5")
I worked out solution using scala, but it looks complicated, is there a more clean and easy way to work out the result? Thanks in advance!
Here is my solution in scala,
val foo=List(("herry","0,1,2"),("herry","1,3"),("herry","3,6"),("herry","4"),("John","5"))
println(GetValue)
def GetValue()={
foo.zipWithIndex.map((tuple: ((String, String), Int)) =>{
val tuples = getrelated(tuple._1, foo)
(tuple._2, tuples)
}).map((tuple: (Int, List[(String, String)])) => tuple._2)
.map((tuples: List[(String, String)]) => (tuples.head._1,tuples.map((tuple: (String, String)) => tuple._2)))
.map((tuple: (String, List[String])) => (tuple._1, tuple._2.mkString(",").split(",").distinct.sorted.mkString(",")))
.distinct
}
def getrelated(start:(String,String),fooList:List[(String,String)]):List[(String,String)]={
val fooListWithout = fooList.filter((tuple: (String, String)) => tuple != start)
val result=fooListWithout
.filter((tuple: (String, String)) => findmatching(tuple._2,start._2))
.flatMap((tuple: (String, String)) => start :: getrelated(tuple,fooListWithout))
if (result.isEmpty)
List(start)
else
result
}
def findmatching(key1:String,key2:String)={
(key1.split(",")++key2.split(","))
.groupBy(identity)
.mapValues((strings: Array[String]) => strings.size)
.exists((tuple: (String, Int)) => tuple._2>1)
}
Let me clarify the algorithm
if the number list has the overlapping number, then group these number as one element
if the number list has no overlapping number, then consider it as independent element
for example,
input: List(("herry","0,1,2"),("herry","1,3"),("herry","7,4"),("herry","4"),("John","5"))
expected output: List(("herry","0,1,2,3" ), ("herry","4,7"), ("John","5"))
input: List(("herry","0,1,2"),("herry","1,3"),("herry","3,6"),("herry","4"),("John","5"))
expected: List("herry","0,1,2,3,6"), ("herry","4"), ("John","5")
input: List(("herry","0,1"),("herry","2,3"),("herry","3,6"),("herry","4"),("John","5"))
expected: List("herry","0,1"),("herry","2,3,6"), ("herry","4"), ("John","5")
My assumption is that tuples for the same key that contain multiple values should be aggregated. It is unclear what should happen in the same value appears singly and as part of a list, e.g. ("herry", "4"), ("herry, "1,4") however it should be simple enough to remove any such cases
val data = List(("herry","0,1,2"),("herry","1,3"),("herry","3,6"),("herry","4"),("John","5"))// Start writing your ScalaFiddle code here
val (singles, multiples) = data.partition{case (name, list) => !list.contains(",")}
val multiplesAggregated = multiples
.groupBy{case (key, _) => key)
.map{
case (key, values) =>
key -> values.flatMap{case (_, numbers) => numbers.split(",")}.distinct.sorted.mkString(",")}.toList
println(multiplesAggregated ++ singles)
Output:
List((herry,0,1,2,3,6), (herry,4), (John,5))

Slick: Read nullable values as option when left join

Problem when using Slick to join: I have 2 tables User and UserInfo and I want to leftJoin them to get user's info. I've tried this:
val q = for{
(user,info) <- User leftJoin UserInfo on (_.id === _.userid)
} yield(user, info)
But the UserInfo table has some nullable field, so when I try to execute the query:
q.map(user_info => (user_info._1,user_info._2)).list
It makes error because user_info._2 has some null values. I know a solution that yield each field in UserInfo and add getOrElse(None) for nullable fields. However, UserInfo has many field so I don't want to use this.
Can anyone help me?
What you CAN do, is this define a function that does the conversion, and then use it in your map:
def nullToOption[A](input: A): Option[A] = input match {
case null => None
case x => Some(x)
}
And then you just use it in your map.
I made a simple example using a simple list:
val lst = List("Hello", null, "hi", null)
val newlst = map lst nullToOption
newList is now the following: List(Some("Hello"), None, Some("hi"), None)
Of course you can modify nullToOption to fit your needs; here's a version that takes tuples:
def nullToOption[A, B](input: (A,B)): (Option[A], Option[B]) = input match {
case (x, y) => (Some(x), Some(y))
case (x, null) => (Some(x), None)
case (null, y) => (None, Some(y))
case (null, null) => (None, None)
}

Querying for close matches in MongoDB and Rails 3

So, I need to write something in Rails 3 that does a query to a MongoDB (If you don't know mongo I don't need the code just some ideas) that can query the data for close matches. For instance, let us say you are searching a collection for {item : a, item2 : b, item3 : c}. And exact match would have all three, but I also want matches that omit one of the three keys. I have two theories on how I should handle this. One would be to do multiple queries to omit certain parts of the data and the other would be to write a complex or statement. I don't feel these are the best solutions though. Could anyone else suggest something to me? Even if it is from an SQL perspective, that would work for me.
I do need something that can be done fast. This is for a search that needs to return results as fast as possible.
Yet another approach would be to use MapReduce.
With it you can calculate how many fields a document matches.
Though it's not very performant approach at the moment (but one of the most flexible).
The code can be something like this:
var m = function() {
var fieldsToMatch = {item: a, item2: b, item3: c};
for(var k in fieldsToMatch) {
if(this[k] == fieldsToMatch[k]) {
emit(this.id, {count : 1}); // emit 1 for each field matched
}
}
};
var r = function(k, vals) {
var result = {count: 0};
vals.forEach(function(v) {
result.count += v.count;
});
return result;
}
db.items.mapReduce(m, r, {out: 'out_collection'});
Why dont you just use mongodb OR, in ruby (using mongoid) you can do this by
Collection.any_of({:item => a, :item2 => b, item3 => c},{:item => a, :item2 => b},{:item => a, :item3 => c},{:item2 => b, item3 => c})
which is equivalent to
db.Collection.find({$or:[{item:a,item2:b,item3:c}],[{item:a,item2:b}],[{item:a,item3:c}],[{item2:b,item3:c}]})