Feel free to copy and paste the code into your fla. It should work to trace vars.
I am trying to create a kids matching game. It selects one letter for the alphabet and will ask them to find that letter from 3 choices. I am also going to randomize the 3 letters they pick from but it is not yet in this code.
My issue is most of the time it is removing an array var using "POP" but sometimes and I get DUPLICATES and sometimes it comes out NULL. What am I doing wrong here?
import flash.events.MouseEvent;
import flash.display.*;
/// Array of the Alphabet
var Alphabet:Array = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
// Arry to hold 3 unique letters
var randArray:Array = new Array();
function getRandomElementOf(array:Array):Object
{
var idx:int=Math.floor(Math.random() * array.length);
// Supposed to remove the letter so can't be chosen again
array.pop()
// Adds 1 of 3 letters to new array
randArray.push(array[idx]);
return array[idx];
}
function testArray(evt:MouseEvent){
var One = getRandomElementOf(Alphabet);
trace(One);
var Two = getRandomElementOf(Alphabet);
trace(Two);
var Three = getRandomElementOf(Alphabet);
trace(Three);
trace("Can you find the letter " + One + "? " + randArray);
// Resets the random Array
randArray = new Array();
// Resets the letters forto be chosen again.
Alphabet = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
}
/// button to click stage to test vars
stage.addEventListener(MouseEvent.CLICK, testArray);
An example shuffler, splicing letters from the alphabet collection:
var alphabet:Vector.<String> = new <String>[ "A", "B", "C", "D", "E", "F", "G",
"H", "I", "J", "K", "L", "M", "N",
"O", "P", "Q", "R", "S", "T", "U",
"V", "W", "X", "Y", "Z" ];
while (alphabet.length > 0)
{
var letter:String = alphabet.splice(int(Math.random() *
alphabet.length), 1)[0];
trace(letter);
}
Example output:
V, M, F, E, D, U, S, L, X, K, Q, H, A, I, W, N, P, Y, J, C, T, O, R, G, B, Z
Applied to your example, here's a reset function to reset the alphabet collection back to its original state, a random letter function to remove a single letter from the alphabet collection, and a shuffle function to randomize the alphabet collection:
/** Alphabet collection */
var alphabet:Vector.<String>;
/** Reset alphabet */
function reset():void
{
alphabet = new <String>[ "A", "B", "C", "D", "E", "F", "G",
"H", "I", "J", "K", "L", "M", "N",
"O", "P", "Q", "R", "S", "T", "U",
"V", "W", "X", "Y", "Z" ];
}
/** Get random letter from alphabet */
function getRandomLetter():String
{
return (alphabet.splice(int(Math.random() *
alphabet.length), 1)[0]);
}
/** Shuffle alphabet collection */
function shuffleAlphabet():Vector.<String>
{
var alphabetShuffled:Vector.<String> = new Vector.<String>();
while (alphabet.length > 0)
{
alphabetShuffled.push(getRandomLetter());
}
return alphabetShuffled;
}
The following pulls a random letter from the alphabet to be found and display the entire alphabet shuffled:
// get a random letter:
reset();
var randomLetter:String = getRandomLetter();
trace("Can you find the letter: " + randomLetter + "?");
// display entire alpha shuffled:
reset();
trace(shuffleAlphabet());
Example game output:
Can you find the letter: Q?
R,I,U,J,Y,D,K,W,T,F,N,G,A,P,X,H,Q,L,S,O,C,V,M,Z,E,B
Can you find the letter: P?
I,F,C,S,J,P,Q,M,D,T,H,X,O,V,W,G,K,A,N,Y,L,U,Z,R,B,E
Can you find the letter: S?
B,U,O,S,C,N,I,E,W,L,P,Q,Z,R,A,G,J,K,Y,M,T,V,X,D,H,F
array.splice()
and not array.pop();
I figured it out.
Related
I can't find the best way to do this.
I have an array with 3 arrays in there(this never change)
var ancho = [String]()
var largo = [String]()
var cantidad = [String]()
var arrayDeCortes = [ancho,largo,cantidad]
arrayDeCortes = [[a,b,c,d,..],[e,f,g,h,..],[i,j,k,l,..]]
I need to get this:
[a,e,i]
[b,f,j]
[c,g,k]
[d,h,l]
My problem is that I don't know how many items there is in each array(ancho,largo,cantidad)
and how access to all of them.
I hope you understand me
You can use reduce(into:_:) function of Array like this:
let arrayDeCortes = [["a","b","c","d"],["e","f","g","h"],["i","j","k","l"]]
let arrays = arrayDeCortes.reduce(into: [[String]]()) { (result, array) in
array.enumerated().forEach {
if $0.offset < result.count {
result[$0.offset].append($0.element)
} else {
result.append([$0.element])
}
}
}
print(arrays)
// [["a", "e", "i"], ["b", "f", "j"], ["c", "g", "k"], ["d", "h", "l"]]
Edit: As #Alexander mentioned in the comments, there is a simpler way of achieving this by using zip(_:_:) function twice.
The following will return an array of tuples:
var widths = ["a","b","c","d"]
var heights = ["e","f","g","h"]
var quantities = ["i","j","k","l"]
let result = zip(widths, zip(heights, quantities)).map { width, pair in
(width, pair.0, pair.1)
}
print(result)
// [("a", "e", "i"), ("b", "f", "j"), ("c", "g", "k"), ("d", "h", "l")]
This is the code that replaces cyrillic symbols to latin:
let cyr = ["а", "б", "в", "г", "д", "Б"]
let latin = ["a", "b", "v", "g", "d", "B"]
var original = self.input.text
for i in 0..<cyr.count {
let target = cyr[i]
let destination = latin[i]
original = original?.replacingOccurrences(of: target, with: destination, options: String.CompareOptions(rawValue: NSString.CompareOptions.caseInsensitive.rawValue | NSString.CompareOptions.literal.rawValue), range: nil)
self.output.text = original;
But it doesn't replace uppercase symbols to upper if i add them in array. It either replaces all lowercases to upper, either upper to lower. How to make it differentiate if it's uppercase symbol or lower and replace it respectively?
You should not use the caseInsensitive option when you want a case sensitive search and replacement. Your code can also be simplified to
let cyr = ["а", "б", "в", "г", "д", "Б"]
let latin = ["a", "b", "v", "g", "d", "B"]
var text = "абвгдБ"
for (src, dest) in zip(cyr, latin) {
text = text.replacingOccurrences(of: src, with: dest)
}
print(text) // abvgdB
Having said that, what you really might want is a transliteration to latin:
let original = "абвгдБ"
let trans = original.applyingTransform(.toLatin, reverse: false) ?? original
print(trans) // abvgdB
Remove the caseInsensitive option and add the uppercase letters to the arrays.
let cyr = ["а", "б", "в", "г", "д", "Б", "А", ...]
let latin = ["a", "b", "v", "g", "d", "B", "A", ...]
var original = self.input.text
for i in 0..<cyr.count {
let target = cyr[i]
let destination = latin[i]
original = original?.replacingOccurrences(of: target, with: destination, options: [.literal], range: nil)
}
self.output.text = original
If I have a structure, say:
struct Subject {
var subjectID: String?
var name: String?
var note: String?
}
And I have two arrays of this structure: Array1 and Array2.
For example:
Array1 = [(subjectID = "T", name = "H", note = "DF"), (subjectID = "F", name = "H", note = "SD")]
Array2 = [(subjectID = "T", name "G", note = "DF"), (subjectID = "R", name = "F", note = "SDF")]
I want to return a new array, which consists of a subset of elements from Array2 that match the subjectID field of Array1 but have different name and/or note elements.
In the example above, the returned array would be:
[(subjectID = "T", name "G", note = "DF")]
As it contains the same subjectID (in this case T) as in Array1 but the name field is different. Note that the fields for this new returned array should be original values from Array2 (ex: you don't need to correct them to match Array1)
Is there an easy way (ex: one-two lines of code) to do this without brute forcing it?
Thanks!
There are good answers here, I prefer to keep the test simple.
First the setup
struct Subject {
var subjectID: String?
var name: String?
var note: String?
}
let array1 = [Subject(subjectID: "T", name: "H", note: "DF"), Subject(subjectID: "F", name: "H", note: "SD")]
let array2 = [Subject(subjectID: "T", name: "G", note: "DF"), Subject(subjectID: "R", name: "F", note: "SDF")]
Now lets look at the actual algorithm. array2.filter returns an array of Subjects in the array2 in which the block returns true. array1.contains returns true if any of the Subjects in array1 returns true. The test itself is exactly what you described. Are the subject id equal and does either the name or the note differ.
let result = array2.filter { s2 in
array1.contains { s1 in
s1.subjectID == s2.subjectID && (s1.name != s2.name || s1.note != s2.note)
}
}
You can do it like this:
let subjectsByID = Dictionary(grouping: array1, by: { $0.subjectID })
let diff = array2.filter { subject in
if let other = subjectsByID[subject.subjectID]?.first {
return subject.name != other.name || subject.note != other.note
} else {
return false
}
}
It groups the subjects in the first array by ID and then filters the second array based on whether or not there is an entry for that ID with a different name or note. You didn't specify what to do if there are multiple entries in the first array with the same ID so it just looks at the first one.
I used a forEach and filter in combination to find the requested elements
var result = [Subject]()
arr1.forEach( { subject in
result.append(contentsOf: arr2.filter( { $0.subjectID == subject.subjectID &&
($0.name != subject.name ||
$0.note != subject.note) }))
})
To get a little cleaner code the check could be made into a function in the struct
struct Subject {
...
func isModifiedComparedTo(_ subject: Subject) -> Bool {
return self.subjectID == subject.subjectID && (self.name != subject.name || self.note != subject.note)
}
}
var result = [Subject]()
arr1.forEach( { subject in
result.append(contentsOf: arr2.filter({$0.isModifiedComparedTo(subject)}))
})
You could filter the second array elements based on the first array elements, as:
let Array1 = [Subject(subjectID: "T", name: "H", note: "DF"), Subject(subjectID: "F", name: "H", note: "SD")]
let Array2 = [Subject(subjectID: "T", name: "G", note: "DF"), Subject(subjectID: "R", name: "F", note: "SDF")]
let result = Array2.filter { subject -> Bool in
for s in Array1 {
if subject.subjectID == s.subjectID && subject.name != s.name && subject.note != s.subjectID { return true }
}
return false
}
result should contains what are you asking for. Keep in mind that it has the complexity of nested iteration (O(n²)).
I'm converting a python programme into swift, and one section uses a for loop to keep every character within a string if it is a letter. In python, it's as simple as using '.isalpha()', is there anything in swift that does this? Code in python:
word = 'hello 123'
new_word = []
for i in word:
if i.isalpha():
new_word.append(i)
Xcode 8 beta4 • Swift 3
extension String {
var lettersOnly: String {
return components(separatedBy: CharacterSet.letters.inverted).joined(separator:"")
}
var lettersArray: [Character] {
return Array(lettersOnly.characters)
}
}
Xcode 7.3.1 • Swift 2.2.1
extension String {
var lettersOnly: String {
return componentsSeparatedByCharactersInSet(NSCharacterSet.letterCharacterSet().invertedSet).joinWithSeparator("")
}
var lettersArray: [Character] {
return Array(lettersOnly.characters)
}
}
Swift 1.x
import UIKit
extension String {
var lettersOnly: String {
return "".join(componentsSeparatedByCharactersInSet(NSCharacterSet.letterCharacterSet().invertedSet))
}
var lettersArray: [Character] {
return Array("".join(componentsSeparatedByCharactersInSet(NSCharacterSet.letterCharacterSet().invertedSet)))
}
}
let word = "hello 123"
let letters = word.lettersOnly // "hello"
let lettersArray = word.lettersArray // ["h", "e", "l", "l", "o"]
Why not just:
let alphabet: [Character] = [
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
"n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"
]
let word = "h4e7l2l8o1"
var answer = [String]()
for letter in word {
if contains(alphabet, letter) {
answer.append(String(letter))
}
}
"".join(answer) // "hello"
or even:
let answer = "".join(filter(word) {contains(alphabet, $0)}.map{String($0)}) // "hello"
This should work:
import Foundation // For playground or REPL
let word = "This is a string !#€%!€#% 123456 åäö é 中國"
let letterCharSet = NSCharacterSet.letterCharacterSet().invertedSet
let newWord = "".join(word.componentsSeparatedByCharactersInSet(letterCharSet))
// Outputs: "Thisisastringåäöé中國"
I am trying to get only 20 random values out of 26 from the lettersthat also have to include elements from the array name. finalArray would look like: ["S", "A", "M", "A", "N", "T", "H", "A", "I", "J", "K", "L", "S", "N", "O","P","Q", "R", "S", "A"](randomly)
So far:
var letters: [String] = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O","P","Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
var name: [String] = ["S", "A", "M", "A", "N","T","H","A"]
//Create finalArray elements
var availableLetters = letters.filter { value in
!contains(name, value)
}
var finalArray = availableLetters + name
I tried to do:
//get 20 objects
var length = name.utf16Count
var beforeArray = finalArray[0...19]
//minus length of the word
var letterCount = beforeArray.count - length
// add missing letters
beforeArray = letters[0...letterCount] + name
Which is obviously wrong and the results are very unstable. What could I use as a simple workaround? How could I implement it?
It seems from your example that you want to take name, and then right-pad it with random letters from the alphabet up to a length of 20. Since it looks like you don’t mind about repeating the random letters, this makes things a lot easier.
The tricky part is generating a sequence of n random numbers up to a maximum. If you have this, you can use these numbers as indices into your alphabet array to pick the random characters. Here’s one way to generate that sequence:
// Struct representing a sequence of count
// random numbers in range 0..<max
struct RandomSequence: SequenceType {
let count: Int
let max: Int
func generate() -> GeneratorOf<Int> {
var i = 0
return GeneratorOf {
i++ < self.count
? Int(arc4random_uniform(UInt32(self.max)))
: nil
}
}
}
Once you have this, it can be used to generate the padding:
let name = Array("SAMANTHA")
let alphabet = Array("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
let targetCount = 20
let paddingCount = targetCount - name.count
let ranseq = RandomSequence(count: paddingCount, max: alphabet.count)
let padding = map(ranseq) { alphabet[$0] }
let padded = name + padding
// padded = ["S", "A", "M", "A", "N", "T", "H", "A", "W", "O", "C", "M", "L", "B", "L", "A", "N", "H", "I", "I"]
If you actually want the name shuffled in with the random letters afterwards, look at the top answer to this question. But it’s probably easiest to do this as a second step to the above technique rather than try and combine both steps together.
It’s worth noting that if name is a string, and you want the result to end up as a string, you don’t need to put in an array for this approach to work:
let name = "SAMANTHA"
let alphabet = Array("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
let targetCount = 20
let paddingCount = targetCount - count(name)
let ranseq = RandomSequence(count: paddingCount, max: alphabet.count)
let padding = map(ranseq) { alphabet[$0] }
let padded = name + padding
// padded = "SAMANTHASLHMPRDYRHFC"