So I was taking a Computer Science test today, and I had to write out a large number of consecutive if statements. All of them had the same basic arguments, just the conditions were different. The whole thing made me wonder if somewhere out there was a multiple argument switch statement. An example of what I'm thinking of is this:
int i = 7;
switch(i > 4, i < 10) {
case T, T:
return "between 4 and 10";
case T, F:
return "greater than 10";
case F, T:
return "less than 4";
case F, F:
return "your computer's thinking is very odd";
}
In this case, the arguments are i > 4 and i > 10, and the T and F are whether the argument is true or not.
I know this example can be easily done other ways, but I'm just trying to show its use. And what if there were 4 arguments, that would be something like 20 if statements each requiring you to retype the conditions.
So my question is, is there any language that does this? Or is it planned for a future language? Or does an even better method exist?
It's hard to say that "no language does this" because there almost certainly is someone working on an experimental language or two that does. However, most procedural languages don't have this kind of feature.
In your example, I think you mean the T, F, etc. to mean "the first expression evaluates to True and the second evaluates to False" (that is, the , is logical AND). This is reminiscent of some decision table languages, where the processing involves finding the first row of a decision table that is satisfied and executing that row's action. Other than that, I don't know of any language that has anything like this.
At least in languages that allow conversion from bool to int, you can handle this pretty easily. You basically just convert the two booleans into a bit-mapped integer value. Since you have two booleans, you can use one directly as bit 0 of your result, and the other multiplied by two as the second bit of your result.
int i = 7;
int range = (i>4) | (i<10)*2;
switch(range) {
case 3: return "between 4 and 10";
case 2: return "greater than 10";
case 1: return "less than 4";
case 0: return "your computer's thinking is very odd";
}
In Mathematica:
Switch[{i > 4, i < 10},
{True, True}, "between 4 and 10",
{True, False}, "greater than 10",
{False, True}, "less than 4",
{False, False}, "your computer's thinking is very odd"
]
Of course, this prints that 4 is less than 4, and 10 is greater than 10, but that's in your pseudocode.
For this specific case one might better write:
Which[
i < 4, "less than 4",
4 <= i <= 10, "between 4 and 10",
i > 10, "greater than 10",
True, "your computer's thinking is very odd"
]
in Python:
i = 7
test = (i > 4, i < 10)
print test
if test == (True, True):
print "between 4 and 10"
elif test == (True, False):
print "greater than 10"
elif test == (False, True):
print "less than 4"
elif test == (False, False):
print "your computer's thinking is very odd"
You can do almost exactly this many languages already, without any special language support. For example, in ruby:
i = 7
case ([i > 4, i < 10])
when [true, true]:
puts "between 4 and 10"
when [true, false]:
puts "greater than 10"
...
end
Or in groovy:
i = 7
switch([i > 4, i < 10]) {
case [[true, true]]:
println "between 4 and 10"
break;
case [[true, false]]:
println "greater than 10"
break;
...
}
I agree with Ted of course - it's hard to say what languages might exist. But your logic can be handled in many.
Your switch just translates first to an if (something like if ((i > 4) && (i < 10)) in many languages).
The switch cases could be modeled as function return values, expressed in some domain-specific way, again, in many languages, even most.
Related
I am trying to figure out how can i distribute particular elements of a list, based on an if statement.
This is the list:
#x = ["american", "assistive", "audio", "blind", "braille", "closed-captioning", "closed-captioning", "deaf", "low", "phone", "question-circle", "question-circle", "sign", "tty", "universal", "wheelchair"]
This is my haml code:
%ul.list-inline
- #x.each do |i|
- if i[0].length < i[1].length
%li
%i{:class=>"fas fa-#{i[0]} fa-2x"}
%span.f6 #{i[0]}
- else
%li
%i{:class=>"far fa-#{i[1]} fa-2x"}
%span.f6 #{i[1]}
What i am trying to do, is to determine the length of each string in the list and compare it to the length of the next string in the list.
Once the second string is determined as being a duplicate, it should go under the else statement.
The problem i am facing, is that by going with i[0], instead of the first string in the list, i am getting the first letter of the each string in the list.
I don't know if my way of using length is the best way to solve this issue, so if anyone else has a better solution i am open for it, as long as it gets the job done.
I am thinking that maybe if i could filter the elements in the list based on which elements are unique and which are duplicates, i could then distribute them accordingly.
But how i do that?
Thank you.
To answer the first part of your question where i[0] or i[1] is returning a single letter instead of the element, let us examine your code:
#x.each do |i|
Here i is the element. So in the first iteration, i is 'american'. So when you call i[0] it returns the first character of the string which is a and i[1] returns m and both their lengths are 1.
Instead, you should modify your code like this:
%ul.list-inline
- #x.each_cons(2) do |current, next|
- if current.length < next.length
%li
%i{:class=>"fas fa-#{current} fa-2x"}
%span.f6 #{current}
- else
%li
%i{:class=>"far fa-#{next} fa-2x"}
%span.f6 #{next}
Regarding the second part of your question, you have defined #x as:
#x = ["american", "assistive", "audio", "blind", "braille", "closed-captioning", "closed-captioning", "deaf", "low", "phone", "question-circle", "question-circle", "sign", "tty", "universal", "wheelchair"]
To fetch unique elements:
#x_uniq = #x.uniq
To fetch duplicates:
#x_dup = #x.each_with_object(Hash.new(0)) { |e,h| h[e] += 1 }.select{ |k,v| v > 1 }.keys
which returns
["closed-captioning", "question-circle"]
In my opinion, using the second way to filter the data and using it is a better solution than comparing elements with their lengths.
Hope this helped.
Use Enumerable#each_cons:
- #x.each_cons(2) do |cur, nxt|
- if cur.length < nxt.to_s.length
...
- else
...
I am searching for synonyms for a particular phrase from a dataset. I have 2 JSON files in which data is stored consisting of synonyms for yes and no . If I query for "not interested" it gives both yes and no phrases/synonyms as result, the expected result is just no phrases/synonyms.
en-gen-yes.json
{
"tag":"en-gen-yes",
"phrases": [
"yes",
"yeah",
"sure",
"suits me",
"interested"
]
}
en-gen-no.json
{
"tag":"en-gen-no",
"phrases": [
"no",
"nope",
"not sure",
"does not suits me",
"not interested"
]
}
query code
query := bleve.NewMatchPhraseQuery("not interested")
req := bleve.NewSearchRequest(query)
req.Fields = []string{"phrases"}
searchResults, err := paraphraseIndex.Search(req)
if err != nil {
log.Fatal(err)
}
if searchResults.Hits.Len() == 0 {
fmt.Println("No matches found")
} else {
for i := 0; i < searchResults.Hits.Len(); {
hit := searchResults.Hits[i]
fmt.Printf("%s\n", hit.Fields["phrases"])
i = i + 1
}
}
The result comes as
[no nope not sure does not suits me not interested]
[yes yeah sure suits me interested]
Expected Result is only
[no nope not sure does not suits me not interested]
The reason that it matches both is that the MatchPhraseQuery you are using will analyze the search terms. You didn't show the IndexMapping here so I can't be sure, but I'll assume you're using the "standard" analyzer. This analyzer removes English stop words, and the English stop word list is defined here:
https://github.com/blevesearch/bleve/blob/master/analysis/lang/en/stop_words_en.go#L281
So, this means that when you do a MatchPhraseQuery for "not interested" you end up just searching for "interested". And that term happens to also be in your "yes" list of synonyms.
It is worth noting that there is a variant called PhraseQuery (without Match) that does exact matching. And while that wouldn't remove the word "not" at search time, it still wouldn't find the match. And the reason is that the word "not" has been removed at index time as well, so and exact match of "not interested" would not find any matches (neither yes or no).
The solution is configure a custom analyzer which either doesn't remove any stop words, or that uses a custom stop word list that doesn't contain the word "not". If you do this, and use it for both indexing and searching, the query you're using should start to work correctly.
I am starting out, so this code may not be as efficient as it could be, but I try. This is a text based game, something happens and the player must decide if he wants to continue or not.
but Everyone is different. so everyone is going to answer with some variation of "yes". How can I get the program to move on if someone types any variation of "yes" the commas give me a syntax error, and i don't know how else to get it to separate the possible answers.
def continueyn():
option1_des1 = raw_input("> ")
if option1_des1 == "yes", "Yes", "forward", "Forward", "Full impulse", "Full Impulse", "yeah", "yup", "Yup", "Yeah":
gravityp1()
elif option1_des1 == "no":
bearing(), userinput()
else:
print "Sorry Captain, I didn't get that. What did you say?"
continueyn()
Using 'or', as pointed out in the comments is incorrect. The correct way to go ahead through this would be either using lists and a loop, or iterating using "in":
Method 1:
option1_des1 = raw_input("> ")
if option1_des1 in {"yes", "Yes", "forward"} :
print "yes"
elif option1_des1 == "no":
print "no"
else:
print "Sorry Captain, I didn't get that. What did you say?"
Method 2:
You can also make a list and then go across values of the list like this-
flag=True
yesList = ['yes', 'Yes', 'forward']
option1_des1 = raw_input("> ")
for element in yesList:
if option1_des1 == element:
print "yes"
flag=False
break;
if option1_des1 == "no" and flag:
print "no"
elif flag:
print "Sorry Captain, I didn't get that. What did you say?"
Even better, you can use regex to match several variations of one type instead of figuring out every permutation. The xample below only covers "yes", but you can make a list of words like in method 2.
import re
pattern = 'yes'
option1_des1 = raw_input("> ")
matchObj = re.search(pattern, option1_des1, re.I)
if matchObj:
print "yes"
elif option1_des1 == "no":
print "no"
else:
print "Sorry Captain, I didn't get that. What did you say?"
Similar to sbhatla's answer you could use a list and use the built in "in" function which returns as a boolean.
yesoptions = ["yes", "Y", "etc"]
if option_des1 in yesoptions:
#runs actions for a yes answer
elif option in:
etcetc
else:
etc..
Straight up, I have read: http://www.couchbase.com/docs/couchbase-manual-2.0/couchbase-views-writing-bestpractice.html and various other pages on Couchbase site, but the following question just bothers me still so I want to double check before rolling this out.
If I have a document about a product, say:
"DocumentType": "productDoc",
"Name": "product",
"Price": 150,
"SellerID": 10,
"DeliverableAUWide": true,
"Colour": "red",
"Size": "large"
say I want a product that is between 100 and 200 then:
if(doc.DocumentType == "productDoc" && doc.Price)
{
emit([1, doc.Price], null)
}
would get me what I want with a start and end key
say I also want to search by size, then
if(doc.DocumentType == "productDoc" && doc.Size)
{
emit([2, doc.Size], null)
}
would get that again with correct key for search.
say I want to search for both at the same time, then:
if(doc.DocumentType == "productDoc" && doc.Size && doc.Price)
{
emit([3, doc.Size, doc.Price], null)
}
would get that.
Now say I want to search by: Price, SellerID, AU deliverable or not, Colour and size....
if(doc.DocumentType == "productDoc"
&& doc.Price
&& doc.SellerID
&& doc.DeliverableAUWide
&& doc.Colour
&& doc.Size
)
{
emit([4, doc.Price, doc.SellerID, doc.DeliverableAUWide, doc.Colour, doc.Size], null)
}
would get that.
But say I also want to be able to search by all of those expect price, I can't use the above, because Price will be null and hence the rest of that emit will be 'useless', because everything will be matched...
so I would need a new view query?? e.g.
if(doc.DocumentType == "productDoc"
&& doc.SellerID
&& doc.DeliverableAUWide
&& doc.Colour
&& doc.Size
)
{
emit([5, doc.SellerID, doc.DeliverableAUWide, doc.Colour, doc.Size], null)
}
The Question
Is this approach correct because it seems that I would need a 'new' emit call for each type of search. So in the .net code I would check what I have re search input from the user and then call the right 'emit' (Note: that is why I have the number in the front of the emits so I can tell them apart later -- for sanity...).
Not only am I concerned about the length of the view that I would have to write, but say I later add a field to the documents, like 'Discount Amount', then I change the view, the re index of that would be massive or? Is this a concern???
Possible alternative to above structure???
Or is it better to have say only,
if(doc.DocumentType == "productDoc" && doc.Price)
{
emit([1, doc.Price], null)
}
if(doc.DocumentType == "productDoc" && doc.Size)
{
emit([2, doc.Size], null)
}
and then when I want a product by price and size call both and get effectively 'lists' of document ids and then 'intersect' these lists and see which id's are in both and then make calls to get the documents. This approach but has significantly more calls to the CB sever and also I would not be able to use the built in skip, limit and startkey_docid for paging. This also seem more performance intensive in the code side. I am presuming this is the 'wrong' mindset for Couchbase, but coming from an environment where the mentality is "less calls to DB = better" I might not be embracing the CB philosophy correctly....
If someone can please:
Confirm the first approach is correct...
the second is wrong
that would be great.
Please let me know if something does not make sense...
Thanks in advance,
Cheers
Robin
Other note: this document is the only document structure that would be in the bucket. I would only have 1 view. 10k documents ~ish.
There is an elegant solution to this but be warned, this approach scales exponentially.
You were on the right track with composite keys.
if(doc.DocumentType == "productDoc" && doc.SellerID && doc.DeliverableAUWide && doc.Colour && doc.Size){
emit([doc.SellerID, doc.DeliverableAUWide, doc.Colour, doc.Size], null)
}
Gives you the ability to filter on all of these fields. Say you wanted all of the documents with a sellerId of 123, a DeliverableAUWide of "true", a color of red, and a size of large, just suffix your query like so.
&startkey[123,"true","red","large"]&endkey[123,"true","red","large",""]
This returns everything that matches those four validations, but your issue is that if you're utilizing this view, you must pass a value for each category.
The solution comes with CouchDB's ability to emit a row multiple times with different keys. Say you want to leave color as a wild card, if you add a new line to your map function
if(doc.DocumentType == "productDoc" && doc.SellerID && doc.DeliverableAUWide && doc.Colour && doc.Size){
emit([doc.SellerID, doc.DeliverableAUWide, doc.Colour, doc.Size], null)
emit([doc.SellerID, doc.DeliverableAUWide, -1, doc.Size], null)
}
you can now query like so
&startkey[123,"true",-1,"large"]&endkey[123,"true",-1,"large",""]
(note: I choose to use -1 because I assume that will never be a valid value on any of these fields. Any value can work, just make sure none of your key values on your documents will actually be whatever you choose.)
and rows with documents of all colors will be return to you. Notice that you can still use the previous query to return all red documents on this same map.
Say you want all of your filters to have the ability to be wildcards. You can use the following map function to recursively generate every emit you're looking for.
function(doc, meta) {
var emitCombos = function(current) {
var dataSet = [doc.SellerID, doc.DeliverableAUWide, doc.Colour, doc.Size]; //add any new keys as they come up here
var current = current || [];
return (current.length === dataSet.length) ? [current] : emitCombos(current.concat(dataSet[current.length])).concat(emitCombos(current.concat(-1)));
};
var allCombos = emitCombos();
//if all three are -1, it's not really filtering, hence the ... .length-1
for (var combo = 0; combo < allCombos.length - 1; combo++) {
emit(allCombos[combo].concat(doc.document.createdDate[1]));
}
}
Using this map, each document will emit rows with these keys
[ 123, 'TRUE', 'RED', 'LARGE' ]
[ 123, 'TRUE', 'RED', -1 ]
[ 123, 'TRUE', -1, 'LARGE' ]
[ 123, 'TRUE', -1, -1 ]
[ 123, -1, 'RED', 'LARGE' ]
[ 123, -1, 'RED', -1 ]
[ 123, -1, -1, 'LARGE' ]
[ 123, -1, -1, -1 ]
[ -1, 'TRUE', 'RED', 'LARGE' ]
[ -1, 'TRUE', 'RED', -1 ]
[ -1, 'TRUE', -1, 'LARGE' ]
[ -1, 'TRUE', -1, -1 ]
[ -1, -1, 'RED', 'LARGE' ]
[ -1, -1, 'RED', -1 ]
[ -1, -1, -1, 'LARGE' ]
As stated earlier, the more filters you use, the more rows you'll emit, therefor bloating your view. So please, emit responsibly.
In Couchbase version 3.x you can use N1QL query language to specify filtering condition to select your json objects without having any views in place.
For example, you should be able issue a query like that:
SELECT *
FROM your_bucket_name
WHERE yourID1 = 'value1' AND yourID2 = 'value2' etc...
Try out N1QL tutorial
Another way could be to utilize Couchbase integration with ElasticSearch and perform search query in ElasticSearch engine that will return you all keys it found based on your search criteria. It also synchronized with your bucket via XDCR streaming.
1- The first approach with the compound key is probably not good for your requirement. The reason why I am saying that is because you can only query the key from left to right ( see http://blog.couchbase.com/understanding-grouplevel-view-queries-compound-keys )
2- The second approach where you do multiple emit is one possible approach but you have to be careful in the way you query to get the proper range/type of data. And as you said if you want to add a new attribute you will have to reindex all the documents.
Why not creating multiple views and take the same approach and do the intersect in your application?
Another approach could be to use the Elasticsearch plugin to delegate the indexing to Elastic in for more complex and full text search queries. http://www.couchbase.com/docs/couchbase-elasticsearch/
PS: The size of the view per itself is not an issue most of the time so do not worry about this.
I'm writing an R function, that is becoming quite big. It admit multiple choice, and I'm organizing it like so:
myfun <- function(y, type=c("aa", "bb", "cc", "dd" ... "zz")){
if (type == "aa") {
do something
- a lot of code here -
....
}
if (type == "bb") {
do something
- a lot of code here -
....
}
....
}
I have two questions:
Is there a better way, in order to not use the 'if' statement, for every choice of the parameter type?
Could it be more functional to write a sub-function for every "type" choice?
If I write subfunction, it would look like this:
myfun <- function(y, type=c("aa", "bb", "cc", "dd" ... "zz")){
if (type == "aa") result <- sub_fun_aa(y)
if (type == "bb") result <- sub_fun_bb(y)
if (type == "cc") result <- sub_fun_cc(y)
if (type == "dd") result <- sub_fun_dd(y)
....
}
Subfunction are of course defined elsewhere (in the top of myfun, or in another way).
I hope I was clear with my question. Thanks in Advance.
- Additional info -
I'm writing a function that applies some different filters to an image (different filter = different "type" parameter). Some filters share some code (for example, "aa" and "bb" are two gaussian filters, which differs only for one line code), while others are completely different.
So I'm forced to use a lot of if statement, i.e.
if(type == "aa" | type == "bb"){
- do something common to aa and bb -
if(type == "aa"){
- do something aa-related -
}
if(type == "bb"){
- do something bb-related -
}
}
if(type == "cc" | type == "dd"){
- do something common to cc and dd -
if(type == "cc"){
- do something cc-related -
}
if(type == "dd"){
- do something dd-related -
}
}
if(type == "zz"){
- do something zz-related -
}
And so on.
Furthermore, there are some if statement in the code "do something".
I'm looking for the best way to organize my code.
Option 1
One option is to use switch instead of multiple if statements:
myfun <- function(y, type=c("aa", "bb", "cc", "dd" ... "zz")){
switch(type,
"aa" = sub_fun_aa(y),
"bb" = sub_fun_bb(y),
"bb" = sub_fun_cc(y),
"dd" = sub_fun_dd(y)
)
}
Option 2
In your edited question you gave far more specific information. Here is a general design pattern that you might want to consider. The key element in this pattern is that there is not a single if in sight. I replace it with match.function, where the key idea is that the type in your function is itself a function (yes, since R supports functional programming, this is allowed).:
sharpening <- function(x){
paste(x, "General sharpening", sep=" - ")
}
unsharpMask <- function(x){
y <- sharpening(x)
#... Some specific stuff here...
paste(y, "Unsharp mask", sep=" - ")
}
hiPass <- function(x) {
y <- sharpening(x)
#... Some specific stuff here...
paste(y, "Hipass filter", sep=" - ")
}
generalMethod <- function(x, type=c(hiPass, unsharpMask, ...)){
match.fun(type)(x)
}
And call it like this:
> generalMethod("stuff", "unsharpMask")
[1] "stuff - General sharpening - Unsharp mask"
> hiPass("mystuff")
[1] "mystuff - General sharpening - Hipass filter"
There is hardly ever a reason not to refactor your code into smaller functions. In this case, besides the reorganisation, there is an extra advantage: the educated user of your function(s) can immediately call the subfunction if she knows where she's at.
If these functions have lots of parameters, a solution (to ease maintenance) could be to group them in a list of class "myFunctionParameters", but depends on your situation.
If code is shared between the different sub_fun_xxs, just plug that into another function that you use from within each of the sub_fun_xxs, or (if that's viable) calculate the stuff up front and pass it directly into each sub_fun_xx.
This is a much more general question about program design. There's no definitive answer, but there's almost certainly a better route than what you're currently doing.
Writing functions that handle the different types is a good route to go down. How effective it will be depends on several things - for example, how many different types are there? Are they at all related, e.g. could some of them be handled by the same function, with slightly different behavior depending on the input?
You should try to think about your code in a modular way. You have one big task to do overall. Can you break it down into a sequence of smaller tasks, and write functions that perform the smaller tasks? Can you generalize any of those tasks in a way that doesn't make the functions (much) more difficult to write, but does give them wider applicability?
If you give some more detail about what your program is supposed to be achieving, we will be able to help you more.
This is more of a general programming question than an R question. As such, you can follow basic guidelines of code quality. There are tools that can generate code quality reports from reading your code and give you guidelines on how to improve. One such example is Gendarme for .NET code. Here is a typical guideline that would appear in a report with too long methods:
AvoidLongMethodsRule