How to check if any elements of an array are not included in another array? - arrays

I'm making a player vs computer Mastermind (the board game) program as part of learning Ruby.
If you don't know Mastermind, basically it's a two-player game where one player creates a code of four colours (i.e. "red red blue yellow") and the opponent tries to guess that code.
The game initializes with a set of available colours and an empty code:
##colours = ["RED", "BLUE", "YELLOW", "GREEN", "ORANGE", "WHITE"]
#code = []
I can ask the user to set a code like this:
puts "Please set your code:"
code = gets.chomp.downcase.split("")
#code << code
The user inputs the code like so: rgby => code = ["RED", "GREEN", "BLUE", "YELLOW"].
(There will be a method which changes, i.e. "r" to "RED", please assume that happens somewhere in my program.)
I want to make sure the player can only use colours included in ##colours, i.e. pxgb would not work.
Pseudo-code would be along the lines of:
If all input colours are found in ##colours, update #code.
or conversely
If any input colours are not found in ##colours, do not update #code (and possibly do something else).
How do I write this? I'm not too familiar with error handling so I was trying to do it with out but I'm willing to learn if that's the best way to go.

You could do the following to check if code has only elements from ##colours
(code - ##colours).empty?
Above expression will be true if code contains only elements from ##colours, else it will be false.
PS: In the code sample in question, code is once shown as containing input from gets and another time shown as an array of processed inputs. In the above solution, I am assuming code = ["RED", "GREEN", "BLUE", "YELLOW"]

You should have a look at the Set object and subset? function.
http://ruby-doc.org/stdlib-2.3.1/libdoc/set/rdoc/Set.html
You can convert your arrays to Sets by using the to_set function on your array

You could just subtract the allowed elements from the input. If the result isn't empty, then there was an element in the input that is not in the list of allowed values:
allowed = [1,2,3]
input = [1,2]
input - allowed #=> []
input = [1,5]
input - allow #=> [5]
As a bonus this returns the element that is not allow and can be used in an error message.

Related

Tradingview, pinescript strategy.comment, multiple comments

I do have a specific tradingview, pinescript command structure I want to maintain, and this includes strategy related arguments as well.
(since I know matlab, I will start with this). In matlab nomenclature, if you have a string array, you can do the following
array = ['dog'; 'cat']
and you can call
array(1) (to display 'dog', or array(2) to display 'cat' ...etc. And if you want to assign it to a new variable, you can do it as
new = array(1); %etc.....
In pinescript what I am trying to do is the following
orderCondition = array.new_string(4)
array.insert(orderCondition, 1, 'open')
array.insert(orderCondition, 2, 'open_new')
array.insert(orderCondition, 3, 'close')
array.insert(orderCondition, 4, 'close_old')
So in this array I am hoping I have something like
[ 'open'; 'open_new'; 'close'; 'close_old' ]
The critical part is in the assignment section. What I want to achieve is the following. I want to declare the first two parts of the array in one strategy comment, and the remaining two in the other, like
strategy.entry("LE", strategy.long, comment=orderCondition[1,2])
strategy.entry("LE", strategy.long, comment=orderCondition[3,4])
so that I group them. And not only that I am also hoping to be able to read those in strategy alert window, as
{{strategy.comment[1-2]}}
{{strategy.comment[3-4]}}
Is this possible? And if possible how can I achieve this? Thank you for your time.

Error when trying to set array in userdefaults: Thread 1: "Attempt to insert non-property list object

I have solved the issue now, thanks for your help. I shouldn't have tried to save arrays with UITextViews, but I should have saved their text as strings instead. Here was the original question:
I have tried a lot, and googled a lot, but I can't solve this problem on my own. Whenever I try to save an array in userdefaults, it just is not working. I get the following error:
Thread 1: "Attempt to insert non-property list object (\n "<UITextView: 0x14001f800; frame = (0 0; 355 180); text = 'D'; clipsToBounds = YES; gestureRecognizers = <NSArray: 0x600003f01d10>; layer = <CALayer: 0x6000031c83e0>; contentOffset: {0, 0}; contentSize: {355, 30}; adjustedContentInset: {0, 0, 0, 0}>"\n) for key content"
I don't know what a non-property list object is. And I do not know how to solve the problem. Below is the lines of code that do not work.
var contentList: [Any] = []
let cl = defaults.array(forKey: "content")!
if cl.count != 0{
contentList += cl
}
contentList.append(label)
defaults.setValue(contentList, forKey: "content")
If I take out the last line of code by turning it into a comment everything runs just fine. How should I replace that line of code? I essentially want to save an array of UITextViews and make it larger every time I call a fucntion (this code is part of a larger function). The reason why I have created another two lists (cl and contentList) is that it helps me with a problem down the line. What I cannot understand however, is why the last line of code doesn't work. If anyone has any ideas, please help me, it would be much appreciated.
Use only String as stated in comments :
var contentList: [String] = []
let cl = defaults.array(forKey: "content")!
if cl.count != 0{
contentList += cl
}
If lbText = label.text {
contentList.append(lbText)
defaults.setValue(contentList, forKey: "content")
}
You can only store a very limited list of data types into UserDefaults, commonly referred to as "property list objects" (Since property list (or plist) files will only store the same data types.
To quote the Xcode docs on UserDefaults, in the section titled "Storing Default Objects":
A default object must be a property list—that is, an instance of (or for collections, a combination of instances of) NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary [or Data, String, NSNumber, Date, Array, or Dictionary types in Swift.] If you want to store any other type of object, you should typically archive it to create an instance of Data.
(I added the equivalent Swift types to the above quote in square brackets, since it looks like Apple hasn't updated it for Swift.)
That's worded a little awkwardly. The idea is that you can only store data of the types listed. Because the Array and Dictionary types are "container" types, you can store any combination of arrays and dictionaries that contain combinations of any of the above types. For example, you can store an array that contains a dictionary, 3 dates, 2 floats, a Double, some Data, and 2 arrays, and those dictionaries and arrays can contain other dictionaries and/or arrays.)
It is almost always wrong to archive UIView objects like UITextViews. You should save the text properties of your text views instead.
If you want to manage a vertical stack of UITextView objects, I suggest adding a vertical stack view to your user interface, and then writing code that adds or removes UITextView subviews to your stack view. You should be able to find plenty of examples of adding and removing objects from stack views online. (It's really easy.)
If you want to manage a scrolling list of feeds of arbitrary length, you might want to use a table view or collection view instead. Those require that you set up a data model and implement a "data source". That takes a little practice to get right, but is very powerful.

Is it possible to Loop through an array of messages and corresponding array of choices in confirm boxes

Newbie here, I have googled and couldn't find an answer.
I have questions and corresponding choices
var questions = ["Would you like A?", "Would you like B?", "Would you like C?"
var choices = [A, B, C]
I want to loop both arrays together in one loop or loopish function so the question is asked in a confirm box, and when I confirm or not, that corresponding choice is logged. For example.
"Confirming Question A also confirms Choice A"
As I have it now the confirm boxes loop through the questions, but my selection for choices is showing as undefined in the console log.
questions.forEach(function(item, index){
confirm(item, choices[index]);
console.log(item, choices[index])
});
I'd like to use the users input towards "if" and "else" statements.
I have this working in chunks of code for A,B and C. But I felt like one loop could knock it out and eliminate a lot of excess code. Maybe wishful thinking?
You can use confirm to fill an array with selected answers or null then use filter to remove the nulls.
var questions = ["Would you like A?", "Would you like B?", "Would you like C?"]
var choices = ["A", "B", "C"]
var sel = []
questions.forEach(function(item, index){
sel.push(confirm(item, choices[index])?choices[index]:null); // null if not selected
console.log(item, choices[index])
});
console.log(sel.filter(x => x!=null)) // remove nulls
Output (choose A and C)
Would you like A?A
Would you like B?B
Would you like C?C
(2) ["A","C"]

Why does map function mutate array of objects when operating on each element's attribute?

I have an array of objects:
class Person
attr_accessor :email
def initialize(email)
#email = email
end
end
array = [
Person.new('hello#gmail.com'),
Person.new('world#gmail.com')
]
I created a clone from the original array to perform map function, and then I mapped over each element to make its email attribute become uppercase:
clone = array.clone
clone.map { |obj|
obj.email.upcase!
obj
}
puts array.inspect # why is the original being mutated
puts clone.inspect
It mutates the original array. I have experimented with both dup and clone. and I get the same result. Why does map mutate the objects when operating on each element's attribute?
You cloned the array containing Person references, but you did not change the array; you changed the Person instances themselves. clone is so-called "shallow clone", which copies only the receiver object, but none of the objects whose references it may contain.
In real-world logic: you took a piece of paper on which you wrote "Jenny, Timmy". Then you copied it to another piece of paper. You then took the first piece of paper, found the people it refered to, and gave them an apple. Then you took the second piece of paper, found the people on it, and wondered where their apples came from. But there's only one Timmy, only one Jenny: you give the first list's Jenny an apple, the second list's Jenny also has one.
If you want to clone something, clone Jenny.
array.map { |person|
person.clone.yield_self { |clone|
clone.email = clone.email.upcase
}
}
(Note that I didn't use clone.email.upcase!. The reason is the same reason all over again: if you clone an object, they will both use the same string for email. upcase! changes that string, which would uppercase both clone's email and the original's email. Thus, we make a new email string for the clone.)
Things like this are best understood by stepping through the visualisation using this tool. However, the tool runs Ruby 2.2, which doesn't know about yield_self; this code is equivalent:
array.map { |person|
clone = person.clone
clone.email = clone.email.upcase
clone
}
You could also write this, though it won't visualise as clearly:
array.map(&:clone).map { |clone|
clone.email = clone.email.upcase
}

deprecation error in sklearn about empty array without any empty array in my code

I am just playing around encoding and decoding but I get this error from sklearn:
Warning (from warnings module):
File "C:\Python36\lib\site-packages\sklearn\preprocessing\label.py", line 151
if diff:
DeprecationWarning: The truth value of an empty array is ambiguous. Returning False, but in future this will result in an error. Use array.size > 0 to check that an array is not empty.
Here is the full code, you can run it yourself in python 3+
My question is why is it saying I use an empty array as I clearly don't in my code, thanks for taking your time to answer my question.
### label encoding ###
import numpy as np
from sklearn import preprocessing
# Sample input labels
input_labels = ["red", "black", "red", "green",\
"black", "yellow", "white"]
# Create label encoder abd fit the label
encoder = preprocessing.LabelEncoder()
encoder.fit(input_labels)
# Print the mapping
print("\nLabel mapping:")
for i, item in enumerate(encoder.classes_):
print(item, "-->", i)
# Encode a set of labels using encoder
test_labels = ["green", "red", "black"]
encoded_values = encoder.transform(test_labels)
print("\nLabels =", test_labels)
print("Encoded values =", list(encoded_values))
# Decode a set of values using the encoder
encoded_values = [3, 0, 4, 1]
decoded_list = encoder.inverse_transform(encoded_values)
print("\nEncoded values =", encoded_values)
print("Decoded labels=", list(decoded_list))
TLDR: You can ignore the warning. It is caused by sklearn doing something internally that is not quite ideal.
The warning is actually caused by numpy, which deprecated truth testing on empty arrays:
The long and short is that truth-testing on empty arrays is dangerous, misleading, and not in any way useful, and should be deprecated.
This means one is not supposed to do something like if array: to check if array is empty. However, sklearn does this in the 0.19.1 release:
diff = np.setdiff1d(y, np.arange(len(self.classes_)))
if diff:
raise ValueError("y contains new labels: %s" % str(diff))
Because your version of numpy is recent enough it complains and issues a warning.
The problem has been fixed in sklearn's current master branch, so I'd expect the fix to be included in the next release.
After updated numpy, the warning was cleared away:
conda update numpy
You can also update it by pip or something else.

Resources