How do I fix the print statement to where it only shows the first person in the collection and so it looks neat and doesn't show all the nonsense - swift

I am trying to print a list of people with their names and their height in order from tallest to shortest. When I do that there is a lot of unnecessary text in the print box. Another problem. I have is when I try to print tallest.first it prints all of the values inside instead of just the first one. I am going to put in the entire code so you can see the full picture.
struct PersonHeight {
let name: String
let height: Int
var formattedHeight: String {
return "\(height / 12)'\(height % 12)"
}
}
let James = PersonHeight(name: "James", height: 50)
let Sam = PersonHeight(name: "Sam", height: 60)
let Dude = PersonHeight(name: "Dude", height: 55)
let array = [James, Sam, Dude]
func personHeight(people: [PersonHeight]) {
var personCount = 0
let shortest = [people.sorted{ $0.height < $1.height}]
let tallest = [people.sorted{ $0.height > $1.height}]
for person in people {
personCount += 1
}
print("There are \(personCount) people and here are their names:")
for person in tallest {
print("\(person).")
}
print("The shortest person is \(shortest.first!) and the tallest person is \(tallest.first!)")
}
personHeight(people: array)
I have tried a few different things and none of them worked. One thing was setting it to a let or variable and it is not working. I also tried just straight sorting it but I got an error for that aswell.

Related

How to solve this Swift problem (AP CP Principles - Structures)

I am currently going through Apple Curriculum books and stumbled across a problem I can't figure out.
There is a structure:
struct Song {
let title: String
let artist: String
let duration: Int
var longestSong = false
}
and an array with 4 songs that have different duration: 90, 200, 150, 440.
The book asks to add a method that checks whether one song is longer than the other.
So, based on previous material I added the following method to my struct:
func isLongerThan(_ song: Song) -> Bool {
return duration > song.duration
}
}
Then the book asks to use a loop in order to find the longest song in the array and print it to the console
(Hint: use a variable to keep track of the longest song and initialize
it to the first one in the array.)
So, I came up with this loop:
for (index, _) in songs.enumerated() {
if index < songs.count-1{
if songs[index].isLongerThan(songs[index + 1]){
songs[index].longestSong = true
print("\(songs[index].title) is longer than \(songs[index+1].title)")
}
} else {
if songs[songs.count-1].isLongerThan(songs[0]){
songs[songs.count-1].longestSong = true
print("\(songs[songs.count-1].title) is longer than \(songs[0].title)")
}
}
}
The next step is to compare those songs with longestSong = true variable until only one song remains. But this isn't a good solution in my opinion.
Is there a better and more elegant way to solve this problem?
UPD
It seems that I have misread the instructions and have gone the wrong way.
With some help I managed to find this solution:
func searchForLongestSong(songs: [Song]) {
var lngstSongIndex = 0
for song in 0..<songs.count {
if songs[song].duration > songs[lngstSongIndex].duration {
lngstSongIndex = song
}
}
print("The longst song is \"\(songs[lngstSongIndex].title)\"")
}
searchForLongestSong(songs: songs)
Since it is an Array you can keep track of the "longest song" by saving the index of the longest song.
Create an Int var to save the index.
Loop through the indices for n in 0..<songs.count
if the duration of songs[n] is greater than songs[largestSongIdx]
Then update the longestSong variables for both accordingly

how do i get an average value for scores in a table view (swift)?

I want to display an average for all values that are inputted into an Entity. Basically, one would press add on the TableView and a pop up would appear asking for a score, which would then add that “exam” to the tableview. I want to be able to add up all the scores and receive an average for them which i can then add to a label. I’ve tried following some other tutorial but it gives me an error.
https://i.stack.imgur.com/P7exB.jpg
https://i.stack.imgur.com/WWITI.jpg
The images above are for context.
var i = 0
var sum = 0
for i in 0...methodsExam.count {
let title = methodsExam[i]
let str : String = title.value(forKey: "score") as! String
sum = sum + Int(str)!
}
let avg = sum/methodsExam.count
averageScore.text = "Average: \(avg)"
Assuming methodsExam is an array of [MethodsExam] you can change the loop to
var sum = 0.0
for item in methodsExam {
if let scoreStr = item.score, let score = Double(scoreStr) {
sum += score
}
}
let average = sum / Double(methodsExam.count)
I am using Double here for more precision.
This could also be done with a high-order function
let average = methodsExam.reduce(into: 0.0) {
if let scoreStr = $1.score, let score = Double(scoreStr) { $0 += score }
} / Double(methodsExam.count)
Since we are dividing with the array count we must also check that the array isn't empty to avoid division by 0, so we can put the code into a function and do this
func calculateAverage(_ array: [MethodsExam]) -> Double {
guard !array.isEmpty else { return 0.0 }
return array.reduce(into: 0.0) {
if let scoreStr = $1.score, let score = Double(scoreStr) { $0 += score }
} / Double(array.count)
}
One caveat, I assumed that score can be nil because of MethodsExam being an NSManagedObject and not because it will hold nil values. If it indeed can hold nil values then you need to consider what to calculate the average on, all values in the array or only non-nil values.

Minimum Window Substring in Swift

I am trying to learn swift by solving interview questions. One of the question that I am trying to solve is as follows.
Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).
Example:
Input: S = "ADOBECODEBANC", T = "ABC"
Output: "BANC"
My implementation is as follows which holds t string characters and its corresponding index retrieved from s.
func minimumWindowSubstring(_ s: String, _ t: String) -> String{
let sChar = [Character](s)
let tChar = [Character](t)
var indexTemp = [[Character:Int]()]
for tc in tChar
{
for (j, sc) in sChar.enumerated()
{
if sc == tc
{
indexTemp.append([tc:j])
}
}
}
return ""
}
what I have in indexTemp array is as follows
Now I wonder how could I able to use this array to find the minimumwindow, I stuck.
I thought it was an interesting problem so I gave it a shot. Instead of using a dictionary I used a simple class to store the range of characters found, as well as a String that stores which characters haven't been found.
It only goes through the main string once, so it should be O(n).
You can run this in the playground.
(I know you wanted help in fixing your code and my answer doesn't do that, but I'm hoping it will provide enough insight for you to adjust your own code)
import Foundation
let string = "ADOBECODEBANC"
let sub = "ABC"
// Create a class to hold the start and end index of the current search range, as well as a remaining variable
// that will store which characters from sub haven't been found
class Container {
var start: Int
var end: Int?
var remaining: String
// Consume will attempt to find a given character within our remaining string, if it has found all of them,
// it will store the end index
func consume(character: Character, at index: Int) {
// If remaining is empty, we're done
guard remaining != "" else { return }
// We're assuming that sub won't have repeating characters. If it does we'll have to chage this
remaining = remaining.replacingOccurrences(of: String(character), with: "")
if remaining == "" {
end = index
}
}
init(start: Int, remaining: String) {
self.start = start
self.remaining = remaining
}
}
// ClosedContainer is similar to Container, but it can only be initialized by an existing container. If the existing
// container doesn't have an end value, the initialization will fail and return nil. This way we can weed out containers
// for ranges where we didn't find all characters.
class ClosedContainer {
let start: Int
let end: Int
init?(container: Container) {
guard let end = container.end else { return nil }
self.start = container.start
self.end = end
}
var length: Int {
return end - start
}
}
var containers = [Container]()
// Go through each character of the string
string.enumerated().forEach { index, character in
// Look for matches in sub
if sub.contains(character) {
// Allow each existing container to attempt to consume the character
containers.forEach { container in
container.consume(character: character, at: index)
}
// Create a new container starting on this index. It's remaining value will be the sub string without the
// character we just found
let container = Container(start: index, remaining: sub.replacingOccurrences(of: String(character), with: ""))
containers.append(container)
}
}
// Convert Containers into ClosedContainers using compactMap, then find the one with the shortest length
let closedContainers = containers.compactMap(ClosedContainer.init)
let maybeShortest = closedContainers.min { $0.length < $1.length }
if let shortest = maybeShortest {
// Convert int to String indices
let start = string.index(string.startIndex, offsetBy: shortest.start)
let end = string.index(string.startIndex, offsetBy: shortest.end)
// Get the result string
let result = string[start...end]
print("Shortest substring of", string, "that contains", sub, "is", result)
} else {
// No range was found that had all characters in sub
print(string, "doesn't contain all characters in", sub)
}

Swift parse csv file for result based on input

I am asking the user to input three values: length, width, and weight
I am referencing a csv file to find results based on the input
Snippet of csv file:
Length,Width,400,500,600,700,800,900,1000,1100,1200,1300,1400,1500,1600,Max2
14,6,16,13,11,9,8,7,6,6,5,5,5,4,4,6500
16,6,18,15,12,11,9,8,7,7,6,6,5,5,5,7400
...
34,7,46,37,31,26,23,20,18,17,15,14,13,12,11,18400
For example, if a user enters:
length: 14
width: 6
weight: 400
I need to display results based on the csv:
16
6,500
The csv file represents this table with the data, here is a snippet:
Tan represents input values, blue represents output
How can I look through the csv file based on the input and find the exact results to display?
I strongly recommend you to start at the data model first. The spreadsheet you show is what I call "pivoted" and is pretty hard to deal with at the application logic layer. Convert it into normalized data, which allows you to perform the operations you need.
struct DataModel {
var length: Int
var width: Int
var weight: Int
var maxWeight: Int
var price: Int // Or whatever the data those teal cells represent
}
let csv = """
Length,Width,400,500,600,700,800,900,1000,1100,1200,1300,1400,1500,1600,Max2
14,6,16,13,11,9,8,7,6,6,5,5,5,4,4,6500
16,6,18,15,12,11,9,8,7,7,6,6,5,5,5,7400
34,7,46,37,31,26,23,20,18,17,15,14,13,12,11,18400
"""
let lines = csv.components(separatedBy: "\n")
let headers = lines[0].components(separatedBy: ",")
var lookupData = [DataModel]()
for line in lines[1...] {
let columns = line.components(separatedBy: ",")
let length = Int(columns[0])!
let width = Int(columns[1])!
let maxWeight = Int(columns.last!)!
for (index, column) in columns.enumerated() where ![0,1,columns.count - 1].contains(index) {
let weight = Int(headers[index])!
let price = Int(column)!
lookupData.append(DataModel(length: length, width: width, weight: weight, maxWeight: maxWeight, price: price))
}
}
// Now you can search for the user's inputs easily
print(lookupData.filter { $0.length == 14 && $0.width == 6 && $0.weight == 400 })
The code in for Swift 4 and does not check for data validity. It assumes that everything is correct and in the expected format. Customize as needed.

swift 3 loop error (taking variable and adding it by itself)

My code does not work right now. I am trying to take names and add it by itself in the loop but the complier is giving me a error message and the code is not being printed.
let names = [Double(2),3,8] as [Any]
let count = names.count
for i in 0..<count {
print((names[i]) + names[i])
}
Because Any doesn't have + operator.
This will give you the result you expected.
If you want to add 2 values and print the result, you need to cast Any to calculatable like Double
let names = [Double(2),3,8] as [Any]
let count = names.count
for i in 0..<count {
if let value = names[i] as? Double {
print(value + value)
}
}
The use of as [Any] makes no sense. You can't add two objects of type Any which is probably what your error is about.
Simply drop it and your code works.
let names = [Double(2),3,8]
let count = names.count
for i in 0..<count {
print(names[i] + names[i])
}
Output:
4.0
6.0
16.0
Better yet:
let names = [Double(2),3,8]
for num in names {
print(num + num)
}