i use the following function to retrieve a random person from an array:
func getRandomPerson() -> String{
if(personArray.isEmpty){
return ""
} else {
var tempArray: [String] = []
for person in personArray{
tempArray += [person.getName()]
}
var unsignedArrayCount = UInt32(tempArray.count)
var unsignedRandomNumber = arc4random_uniform(unsignedArrayCount)
var randomNumber = Int(unsignedRandomNumber)
if tempArray.isEmpty {
return ""
} else {
return tempArray[randomNumber]
}
}
}
I would like to use this function inside an array of strings, Like this:
var theDares: [String] = ["Dare1 \(getRandomPerson())", "Dare2", "Dare3", "Dare4", "Dare5"]
But when i use the functions, it only runs the function once. Can you make the function run everytime you use the "Dare1" in this instance.
Thanks in advance
I think you are asking if you can set up your array so every time you fetch the object at index 0, it re-builds the value there.
The short answer is no. Your code is creating an array of strings, and the item at index 0 is built ONCE using a function call.
However, it is possible to make a custom class implement the subscript operator. You could create a custom object that looks like an array and allows you to index into it using an Int index. In response to the index operator you could run custom code that built and returned a random string.
Since it sounds like you're a beginning programmer creating a custom class the implements the subscript operator might be beyond your current abilities however.
Try like this:
let personArray = ["John", "Steve", "Tim"]
var randomPerson: String {
return personArray.isEmpty ? "" : personArray[Int(arc4random_uniform(UInt32(personArray.count)))]
}
println(randomPerson) // "Steve"
Related
var brachNames = ["AP","AP","AP","AS","AS","AS","BR","BR","BR"]
var overAllTaget = ["84","84","84","84","84","84","84","84","84"]
var overAllSold = ["135","135","135","135","135","135","135","135","135"]
extension Array where Element : Hashable {
func removeDups() -> [Element] {
var uniquedElements = Set<Element>()
return filter { uniquedElements.insert($0).inserted }
}
}
I want this type of output - [AP,84,135,AS,84,135,BR,84,135]
Since you've 3 different Arrays, you need to first combine these to get an Array of Arrays using zip(_:_:) and map(_:), i.e.
var arr = zip(brachNames, zip(overAllTaget, overAllSold)).map { [$0.0, $0.1.0, $0.1.1] }
Now, use Set to filter out the duplicates. Then use flatMap(_:) to get a single result Array, i.e.
let result = Array(Set(arr)).flatMap{ $0 } //["AP", "84", "135", "AS", "84", "135", "BR", "84", "135"]
Note: Set is unordered. So, the sequence of the result might change.
Another approach would be to create a struct with the required fields (brachName, overallTarget, overallSold), comply to Hashable and apply something like this:
https://www.hackingwithswift.com/example-code/language/how-to-remove-duplicate-items-from-an-array
This way you could keep the order, if that's important.
It would be much better to work with an array of a custom type instead of 3 different arrays of data to make the code clearer and to avoid simple mistakes when accessing the data. Below is an example of such solution using a struct to hold the data
struct BranchData: Hashable {
let branchName: String
let overallTarget: Int
let overallSold: Int
}
var set = Set<BranchData>()
for (index, branch) in brachNames.enumerated() {
guard index < overAllSold.count, index < overAllTaget.count else {
break
}
set.insert(BranchData(branchName: branch, overallTarget: Int(overAllTaget[index]) ?? 0, overallSold: Int(overAllSold[index]) ?? 0))
}
To support the specific output with all values in an array we can add a computed property
extension BranchData {
var propertyArray: [String] {
[branchName, String(overallTarget), String(overallSold)]
}
}
let output = set.flatMap { $0.propertyArray }
or a more direct approach
let output = set.flatMap { [$0.branchName, $0.overallTarget, $0.overallSold] }
I have a computed array which is full of tags and updates depending on what selection i make in the select box. I would like to take this array and pass it to a method and then run a method to update what “results” have an active class. Although I get an array saying I can’t run forEach on this element.
Been through a few topics and understand computed properties dont work like that but surely there is a way around this.
https://jsfiddle.net/39jb3fzw/6/
Short Snippet
methods: {
updateOutput() {
var tags = this.tagArray;
tags.forEach(function(tag) {
console.log(tag);
})
}
},
computed: {
concatenated: function () {
var ret = this.selected.concat(this.selected2, this.selected3);
this.tagArray = ret;
//this.updateOutput();
return ret;
}
}
Full Output
https://jsfiddle.net/39jb3fzw/6/
Thanks again :slight_smile:
It looks like the issue is the line:
var ret = this.selected.concat(this.selected2, this.selected3);
That line of code is returning an empty string rather than an array. This is because this.selectedX is a string rather than an Array. This explains why tag.forEach is undefined. forEach doesn't exist on the String prototype.
You can create this an array instead be doing
var ret = [ this.selected, this.selected2, this.selected3 ]
From there you can set this.tagArray to ret
Hope this helps
I am trying to make a main menu for an Mac application as a beginning task to learn about Swift. Here is my code, which does not work.
In the AppDelegate
import Foundation
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate
{
#IBOutlet weak var window: NSWindow!
//private let mainWindow = NSWindow(frame: NSWindow.mainScreen().bounds)
//let mainWindow = NSWindow()
//let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(NSSquareStatusItemLength)
func applicationDidFinishLaunching(aNotification: NSNotification)
{
// Insert code here to initialize your application
let menuData = [getMainMenuItems]
//[makeMainMenu, menuData]
}
}
And then in a different project file, named Swift_FileManager
import Foundation
import Cocoa
class menuArrayObject
{
var title: String = ""
var subMenuTitles: [String] = []
}
func getMainMenuItems (menuData:Array<AnyObject>) -> AnyObject
{
//Make a new menu array
var menuData = [AnyObject]()
let arrayObject1 = menuArrayObject()
arrayObject1.title = "Project"
arrayObject1.subMenuTitles = ["New Project","Open Project","Save Project", "Quit Project"]
menuData.append(arrayObject1)
return menuData
}
The code compiles but the function getMainMenuItems is never called.
Can somebody shed some light on the (probably very simple) issue here? Thanks in advance
let menuData = [getMainMenuItems]
This line (probably) isn't doing what you think it's doing. What it's doing is creating an array of [(Array<AnyObject>)->(AnyObject)] type (an array of functions that take an array of AnyObjects as input, and return an AnyObject) – and adding your getMainMenuItems function to it.
It's not calling your function at all.
In order to call a function, you need to use a pair of brackets (), containing the required input. In this case, your getMainMenuItems method expects an array of AnyObjects (although it never appears to actually use them).
For example:
let menuData = getMainMenuItems([/* Insert your objects here */])
Although that all being said, I'm not entirely sure that your getMainMenuItems function actually needs an input, as you never use it. I think you're looking for something like this:
func getMainMenuItems() -> [MenuArrayObject] {
// create an empty array of MenuArrayObjects
var menuData = [MenuArrayObject]()
let arrayObject1 = MenuArrayObject()
arrayObject1.title = "Project"
arrayObject1.subMenuTitles = ["New Project","Open Project","Save Project", "Quit Project"]
menuData.append(arrayObject1)
return menuData
}
Note that the function no longer has an input, and I've replaced AnyObject with [MenuArrayObject]. It's best to be as type specific as you can in Swift (and pretty much every other OOP language), so you should really steer away from AnyObject unless you have good reason to use it.
Now you can just invoke your function like this:
let menuData = getMainMenuItems()
and it will return an array of MenuArrayObjects.
If you're trying to make the function so that it'll add an object to an already existing array, then you can use an inout parameter in your function. This will let you pass an array into your function, which it can modify.
For example:
func getMainMenuItems(inout menuData:[MenuArrayObject]) {
let arrayObject1 = MenuArrayObject()
arrayObject1.title = "Project"
arrayObject1.subMenuTitles = ["New Project","Open Project","Save Project", "Quit Project"]
menuData.append(arrayObject1)
}
You can then call it like so:
// an existing array of MenuArrayObjects
var menuDataArray = [MenuArrayObject]()
// call function with array – which it will append an element to
getMainMenuItems(&menuDataArray)
The code let menuData = [getMainMenuItems] is just creating an array containing the function. I'm guessing that you mean to call the function instead. That looks something like:
let menuData = getMainMenuItems([])
In applicationDidFinishLaunching you need to instantiate menuArrayObject:
let myMenuArray = menuArrayObject()
And then call it:
let menuData = myMenuArray.getMainMenuItems()
Your getMainMenuItems method, it seems looking at what you wrote in the method, should be defined as:
func getMainMenuItems() -> [AnyObject]
I am learning how to build apps and working with Swift for this project.
I had a buddy help me pull data in from a website and it looks like he created classes with variables and mapped them to certain extensions (IE "Username") so when I call the variable data such as profile I would call it. The below uses luck_30 able to store "Stats.luck_30"
luck_30.text = profile.luck_30
So inside one of my variables that is in this "Profile" class is setup into an array. I can pull the array out of the class, but I can't seem to do for while statement replacing the [#] with a variable from the for command.
func aliveWorkers(profile: Profile) -> NSNumber{
var myworkers : Array = profile.workers!
//this test works and returns the proper value
var testworker: NSNumber = myworkers[0].alive!
println("The satus of the test worker is " + testworker.description)
/* This code is giving error "Could not find member alive" it does not ifor var
for ifor in myworkers{
var thisworker: NSNumber = myworkers[ifor].alive! as NSNumber
}
*/
return 42
}
Your variable ifor is not a counter, it is an actual object. You could do something like this:
for worker in myWorkers {
let workerIsAlive = worker.alive!
}
Alternatively, if you need the index,
for i in 0 ..< myWorkers.count {
let worker = myWorkers[i]
let workerIsAlive = worker.alive!
}
If you need both:
for (i, worker) in enumerate(myWorkers) {
let workerIsAlive = worker.alive!
}
And as a matter of style, I would stay away from NSNumber and use Int or Bool or whatever the data actually is. Also, it looks like the alive variable should not be optional, as you're unwrapping it everywhere. To avoid "mysterious" crashes later, you may want to think about making it a non-optional type.
when using a for in loop, your loop variable isn't an index, its the objects you're looping through. so..
func aliveWorkers() {
var myworkers = [1, 2, 3]
//this test works and returns the proper value
let testworker = myworkers[0]
print("The satus of the test worker is \(testworker)")
for ifor in myworkers {
print(ifor)
}
}
Notice a few things... you don't need to use + to concatenate those strings. you can just use string interpolation. \(variable) inserts the value of variable in the string.
Try to use let instead of var when you don't change the variable. You don't need to explicitly define type on variables either.
I have created an array as shown below
protected function getMyArray(dataArray:Array):Array
{
var labelList:Array=new Array;
for each (var property:Object in dataArray)
{
if (labelList[property.bucketTime] != property.bucketTime)
labelList[property.bucketTime]=property.bucketTime;
}
return labelList;
}
Is it possible to sort the array labelList based on property.bucketTime?
Edit: Sample input dataArray will be like this :
var tempObj:Object = new Object;
tempObj.bucketTime = DateField.stringToDate("30-01-2010", "DD-MM-YYYY").time;
tempObj.score = 76;
dataArray.addItem(tempObj);
tempObj = new Object;
tempObj.bucketTime = DateField.stringToDate("13-02-2010", "DD-MM-YYYY").time;
tempObj.score = 21;
dataArray.addItem(tempObj);
tempObj = new Object;
tempObj.bucketTime = DateField.stringToDate("30-03-2010", "DD-MM-YYYY").time;
tempObj.score = 10;
tempArry.addItem(tempObj);
Unless bucketTime is a number; then you aren't actually populating the array. You're just adding properties to the Array Object, almost like it were a Dictionary. I've seen a Dictionary called Associative Array's and Structures in other languages.
If that is the case, an you're using the Array class as a dictionary, then there is no way to sort it. The very nature of such a structure is that they are not sortable.
However, if property.bucketTime is a number, and you are trying adding items to the array as if they were an array, you can sort using the Array.sort or Array.sortOn methods.
Atlast I sorted the labelList Array.Please find my solution below. Let me know if there is any better way to achieve this.
var termObject:Object = ObjectUtil.getClassInfo(labelList);
var termsArray:Array = termObject.properties;
var sortedColumnArray:Array = new Array;
for each(var term:Object in termsArray){
if(labelList.hasOwnProperty(term)){
sortedColumnArray.push(labelList[term]);
}
}