Filter specific values from array of string - swift

I have an array of following values
["130896-220","130897-901","130011-990","130012-991"]
and I am filter out of only those values which contain 900 to 999 at end of value.
I need following result of array ["130897-901","130011-990","130012-991"].

Simply call filter(_:) on arr with the relevant condition to filter the elements within the range 900...999
let arr = ["130896-220","130897-901","130011-990","130012-991"]
let range = (900...999)
let result = arr.filter({
if let str = $0.components(separatedBy: "-").last, let num = Int(str) {
return range.contains(num)
}
return false
})
print(result) //["130897-901", "130011-990", "130012-991"]

An alternative is Regular Expression
let array = ["130896-220","130897-901","130011-990","130012-991"]
let filteredArray = array.filter{$0.range(of: "^\\d{6}-9\\d{2}$", options: .regularExpression) != nil}
The pattern "^\\d{6}-9\\d{2}$" searches for
six digits followed by
one hyphen followed by
9 followed by
two other digits

A little bit unconventional Objective-C solution:
NSArray *data = #[#"130896-220", #"130896-901", #"130896-903"];
// We'll fill this array with the final filtered result
NSMutableArray* filteredData = [[NSMutableArray alloc] init];
for (NSString* str in data) { // Iterate between strings
int value = [[str componentsSeparatedByString:#"-"][1] intValue];
if(value > 900 && value < 1000){
[filteredData addObject:str];
}
}
Edit:
Inside the for I use the method componentsSeparatedByString:#"" this will return an array with strings separated by the entered value. In this case we know that we want the value after the "-" character so we access the second index of the array directly ([1]).
Lastly, we check if the value is compressed between the values we want. If so, is added to the filtered array.

Related

sum only values with specified bool with core data

I have a tableview with values. The database is made with core data. You can set the values to true or false. I only want to sum the values with true. To sum the values i have this code.
func printData() {
//Shorthand Argument Names
//let request: NSFetchRequest<Gegenstand> = Gegenstand.fetchRequest()
//let records = try! context.fetch(request) as [NSManagedObject]
let sum = ViewController.liste.reduce(0) { $0 + ($1.value(forKey: "gewicht") as? Double ?? 0) }
print("Gesamtgewicht: \(sum) kg")
gewicht = sum
if gewicht > 3500 {
gewichtLabel.textColor = .red
gewichtLabel.text = "\(gewicht) kg"
}
}
I tried it with an if-function but i don't know to use it with core data.
Create a coreData fetchRequest with isValue=true,
Calculate the sum of return fetchRequest
func fetchAllWithTrue() -> [Gegenstand] {
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: Gegenstand)
fetchRequest.predicate = NSPredicate(format: “isValue== YES")
do {
let fetchedObjects = try coreDataManager.context.fetch(fetchRequest) as? [Gegenstand]
return fetchedObjects
} catch {
print(error.localizedDescription)
return [Gegenstand]()
}
}
You can do all of it in Core Data if you want. Filter for true filtering with an NSPredicate, and have Core Data calculate the sum using NSExpression.
First set up the fetch request to get only entries where the property is true and make sure it returns dictionary-type results (I don't know what your boolean is called, so here I'm calling it flag. Put your property name there):
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Gegenstand")
fetchRequest.resultType = .dictionaryResultType
fetchRequest.predicate = NSPredicate(format: "flag = true")
Then set up an NSExpressionDescription that can get the sum of gewicht values:
let sumExpression = NSExpression(format: "sum:(gewicht)")
let sumExpressionDescription = NSExpressionDescription()
sumExpressionDescription.expression = sumExpression
sumExpressionDescription.resultType = .double
sumExpressionDescription.name = "gewichtSum"
What this does is create a new kind of property that Core Data understands where the value is the sum the values of gewicht and is named gewichtSum. Fetch requests know how to use that kind of property. You do it like this:
fetchRequest.propertiesToFetch = [ sumExpressionDescription ]
Since the fetch uses dictionaryResultType, running the fetch returns an array of dictionaries. It's an array because fetch always returns an array, but here there's only one entry. The dictionary in that array entry has a key called gewichtSum for a Double property that was calculated from the expression above. You get the value like this:
do {
let result = try context.fetch(fetchRequest)
if result.count > 0,
let sumInfo = result[0] as? [String:Double],
let gewichtSum: Double = sumInfo["gewichtSum"] {
print("Sum: \(gewichtSum)")
}
} catch {
...
}
The print statement above prints the sum of all gewicht values where flag is true. It only includes true values for flag because of the NSPredicate, and it contains the sum because of the expression description.

filtering an array and counting the number of elements

I am trying to count the number of items in an array which correspond to a particular attribute.
func subCount() {
let arr = subDS.subFolders // array
var counts: [String: Int] = [:]
arr.forEach { counts[$0.parentFolder!, default: 0] += 1 }
print(Array(counts.values))
}
when the code above is executed, if the count is zero it does not appear in the array. Also the order of the array formed in an incorrect order.
You can use filter method
for example :
var filterArray = subDS.subFolders.filter { $0. parentFolder == 0 }
let count = filterArray.count
The first $0 is from the filter and it represents each subFolders.

How to mask a String to show only the last 3 characters?

I just tried to mask String as below, but I didn't find what I want after do some search and research.
string a = "0123456789"
masked = "xxxxxxx789"
I modified solutions in this questions http://stackoverflow.com/questions/41224637/masking-first-and-last-name-string-with but it just change the String that doesn't match with the pattern. I have no idea how to change the pattern to match with what I mean.
You can get the last 3 characters of your string using the collection method suffix(_ maxLength: Int) and fill the other part of the string repeating the "x":
edit/update
Swift 4 or later
extension StringProtocol {
var masked: String {
return String(repeating: "•", count: Swift.max(0, count-3)) + suffix(3)
}
}
let string = "0123456789"
print(string.masked) // "•••••••789\n"
This does exactly what you want:
let name = "0123456789"
let conditionIndex = name.characters.count - 3
let maskedName = String(name.characters.enumerated().map { (index, element) -> Character in
return index < conditionIndex ? "x" : element
})
print("Masked Name: ", maskedName) // xxxxxxx789
What happens here is that you get an array of the characters of the string using enumerated() method, then map each character to a value based on a condition:
If the index of the character is less than condtionIndex we replace the character with an x (the mask).
Else, we just leave the character as is.
who want this in obj C, can use this
NSString *phone = #"0123456789";
NSString *lastChr = [phone substringFromIndex: [phone length] - 3];
NSMutableString *mask = [[NSMutableString alloc]init];
for (int i=0; i<[phone length]-3; i++) {
[mask appendString:#"*"];
}
[mask appendString:lastChr];
I use this, very simple:
var pan: String?
var maskedPan: String { return pan.enumerated().map({ return ($0 < 6 || $0 > 11) ? String($1) : "*" }).joined()}
where $0 is index and $1 is iterated character

How to get the first word before a dash in Swift?

I would like to get the first year of this string. The one before the dash -: "2007-2016"
How can I achieve this within Swift 3?
I did some research and there is an function called substring or index but doesn't know which one I should use.
What I want to achieve is a sort function that will sort on year. So I think the best way to do this is using the first year (from year). There are also objects that only contains one year...
Use index(of:) and substring(to:).
Following your comment, I've also added an example to get the second year.
let str = "2007-2016"
if let idx = str.characters.index(of: "-") {
let year1 = str.substring(to: idx)
print(year1)
let year2 = str.substring(from: str.index(after: idx))
print(year2)
}
Two (other) solutions:
let string = "2007-2016"
let year1 = string.components(separatedBy: "-").first!
let year2 : String
if let range = string.range(of: "-") {
year2 = string.substring(to: range.lowerBound)
} else {
year2 = string
}
If there is no dash in the string the result is the whole string.

String convert to Int and replace comma to Plus sign

Using Swift, I'm trying to take a list of numbers input in a text view in an app and create a sum of this list by extracting each number for a grade calculator. Also the amount of values put in by the user changes each time. An example is shown below:
String of: 98,99,97,96...
Trying to get: 98+99+97+96...
Please Help!
Thanks
Use components(separatedBy:) to break up the comma-separated string.
Use trimmingCharacters(in:) to remove spaces before and after each element
Use Int() to convert each element into an integer.
Use compactMap (previously called flatMap) to remove any items that couldn't be converted to Int.
Use reduce to sum up the array of Int.
let input = " 98 ,99 , 97, 96 "
let values = input.components(separatedBy: ",").compactMap { Int($0.trimmingCharacters(in: .whitespaces)) }
let sum = values.reduce(0, +)
print(sum) // 390
For Swift 3 and Swift 4.
Simple way: Hard coded. Only useful if you know the exact amount of integers coming up, wanting to get calculated and printed/used further on.
let string98: String = "98"
let string99: String = "99"
let string100: String = "100"
let string101: String = "101"
let int98: Int = Int(string98)!
let int99: Int = Int(string99)!
let int100: Int = Int(string100)!
let int101: Int = Int(string101)!
// optional chaining (if or guard) instead of "!" recommended. therefore option b is better
let finalInt: Int = int98 + int99 + int100 + int101
print(finalInt) // prints Optional(398) (optional)
Fancy way as a function: Generic way. Here you can put as many strings in as you need in the end. You could, for example, gather all the strings first and then use the array to have them calculated.
func getCalculatedIntegerFrom(strings: [String]) -> Int {
var result = Int()
for element in strings {
guard let int = Int(element) else {
break // or return nil
// break instead of return, returns Integer of all
// the values it was able to turn into Integer
// so even if there is a String f.e. "123S", it would
// still return an Integer instead of nil
// if you want to use return, you have to set "-> Int?" as optional
}
result = result + int
}
return result
}
let arrayOfStrings = ["98", "99", "100", "101"]
let result = getCalculatedIntegerFrom(strings: arrayOfStrings)
print(result) // prints 398 (non-optional)
let myString = "556"
let myInt = Int(myString)