Array sorting by property - arrays

I have a set of object array like this:
[ProductDetails(name: "Tai Tou Choy",
productDescription: "",
deliveryTime: "24 hours",
img1: "https://api.com.my/images/data/4983-img1-1463122485.jpg",
thumbImg1: "https://api.com.my/images/data/thumbs/4983-img1-1463122485.jpg",
img2: "",
thumbImg2: "",
img3: "",
thumbImg3: "",
videoLink: "",
sku: "0000000004983",
relatedProduct: "",
priceOption: [PriceOption(id: 9931,
label: "500g",
price: "4.56",
promo: "0",
quantity: 999)],
deliveryZone: [DeliveryZone(zone: "3")],
deliveryZoneName: [DeliveryZoneName(zoneName: "Within Klang Valley")],
qrCode: "4983"),
ProductDetails(name: "Penguin Asam Jawa",
productDescription: "",
deliveryTime: "24 hours",
img1: "https://api.com.my/images/data/1004-img1.jpg",
thumbImg1: "https://api.com.my/images/data/thumbs/1004-img1.jpg",
img2: "",
thumbImg2: "",
img3: "",
thumbImg3: "",
videoLink: "",
sku: "0000000001004",
relatedProduct: "",
priceOption: [PriceOption(id: 6971,
label: "1 kg",
price: "4.80",
promo: "0",
quantity: 864)],
deliveryZone: [DeliveryZone(zone: "3")],
deliveryZoneName: [DeliveryZoneName(zoneName: "Within Klang Valley")],
qrCode: "1004")]
I wanted to do price sorting from above the arrays, which the PriceOption array is store inside the main array as an object array too. How do i do sorting from PriceOption? I try to do it in this way :
for i in self.productList{
i.priceOption.sortInPlace{
$0.price.localizedCaseInsensitiveCompare($1.price) == NSComparisonResult.OrderedDescending
}
}
Which return an error "Cannot use mutating member on immutable value :'i' is a 'let' constant."
How to do this?

This how I solve issue that you present. I am using sorted method of the array class.
Solution:
self.productList.sorted{ Float($0.priceOption.first!.price)! > Float($1.priceOption.first!.price)! }

Try this
for i in self.productList {
i.priceOption.sort { $0.price < $1.price } }

The answer for swift 3 is as following
Ascending:
self.productList = self.productList.sorted(by:
{(first: ProductDetails, second: ProductDetails) -> Bool in
first.price > second.price
}
)
Descending:
self.productList = self.productList.sorted(by:
{(first: ProductDetails, second: ProductDetails) -> Bool in
first.price > second.price
}
)

Related

Picking a random element from Swift Class

This is a model of my makeshift database
var categories: [Category] = [
Category(name: "X",
sign: [Sign(code: "X-1", name: "***", description: "", picture: ""),
Sign(code: "X-2", name: "***", description: "", picture: "")]),
Category(name: "Y",
sign: [Sign(code: "Y-1", name: "Yyy", description: "", picture: ""),
Sign(code: "Y-2", name: "yyy", description: "", picture: "")]),
Category(name: "Z",
sign: [Sign(code: "Z-1", name: "Zzz", description: "", picture: ""),
Sign(code: "Z-2", name: "ZZZ", description: "", picture: "")])
]
I need to get one random element of any category (not one from each) from this base and print it as sign.code
I prepared the variable to store the value:
var RandomSign: Sign
And tried to do it with for loop:
func randomSign() {
for categorie in categories {
randomSign = categorie.sign.randomElement()
But, in the result, my loop generate me random element from each category, and finally save only random from the last one. I would like print for example "X-2" in my consol as random selected value.
Why not pick a random category and then a random sign from that random category?
func randomSign() {
randomSign = categories.randomElement()!.sign.randomElement()!
}
This code will crash if any of the arrays are empty. It would be safer if randomSign was optional then you can do:
func randomSign() {
randomSign = categories.randomElement()?.sign.randomElement()
}
Or you could fallback to a default Sign:
func randomSign() {
randomSign = categories.randomElement()?.sign.randomElement() ?? Sign(code: "empty", name: "***", description: "", picture: "")
}

Swift fixed sized array changes size after every append

I have created a fixed size array to collect user data from textfields. Each textfield is in a different cell. So I'm collecting all user answers in one fixed array
var userSelectionText = [String](repeating: "", count: 17)
What is really strange is that the array size gets enlarged with +1 every time I insert a string in a certain index in the array according to the row number of the cell.
self.userSelectionText.insert(diseaseSelectionArray[row], at: tappedTextFieldTag)
When I print out the array at first load of the view I have 17 items
["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]
After adding a string in a certain index of the fixed sized array I have 17 items + 1
["", "", "No", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]
Why? I need them fixed to reflect the exact number of rows in the tableview
You're inserting (adding) elements into the array, but what you want is to replace the existing elements:
var array = ["", "", ""]
print(array)
print(array.count)
array.replaceSubrange(Range(0 ... 0), with: ["1"])
print(array)
print(array.count)
This outputs:
["", "", ""]
3
["1", "", ""]
3
Or, even shorter (thanks #Joakim Danielson):
array[0] = "1"

Typescript merging 2 arrays and increase qty if they have the same id

I'm doing with my Angular 8 project and I want to merge 2 arrays into 1 and increase qty if they have the same value in the object. I have tried a few times by myself and it does not really work well.
mergedOrderList: any[]= [];
lstOldOrder: any[] = [
{id: "", products_id: "", qty: 1, ...},
{id: "", products_id: "", qty: 1, ...},
{id: "", products_id: "", qty: 1, ...},];
lstNewOrder: any[] = [
{id: "", products_id: "", qty: 1, ...},
{id: "", products_id: "", qty: 1, ...},
{id: "", products_id: "", qty: 1, ...},];
lstNewOrder.forEach(newOrder => {
let isDubplicated: boolean = false;
lstOldOrder.forEach(oldOrder => {
if (newOrder.products_id == oldOrder.products_id) {
oldOrder.qty += newOrder.qty;
isDubplicated = true;
mergedOrderList.push(oldOrder);
}
});
if (!isDubplicated) {
mergedOrderList.push(newOrder)
}
});
I did like this and they work when they both have the same products_id. But when new order doesn't have products_id. They skip my old order and add only new order to the list. I'm not quite sure I'm done it right. Thanks
See the problem is that you are only adding data from lstOldOrder in mergedOrderList if the
product_id of new list item matches with any item in old list.
So you are not able to see any item from old list if all the items are new in lstNewOrder
Instead what you should do is :
Add the item to the mergedOrderList but increase the quantity if there is a match.
mergedOrderList = [];
lstOldOrder = [
{ id: "1", products_id: "", qty: 1 },
{ id: "2", products_id: "", qty: 1 },
{ id: "3", products_id: "", qty: 1 },
];
lstNewOrder = [
{ id: "4", products_id: "", qty: 1 },
{ id: "5", products_id: "", qty: 1 },
{ id: "1", products_id: "", qty: 1 },
];
lstNewOrder.forEach((newOrder) => {
Oindex = -1;
lstOldOrder.forEach((item, index) => {
if (item.id == newOrder.id) {
Oindex = index; // Getting the Index of that item in old array.
}
});
if (Oindex != -1) { // if that item was in old Array
newOrder.qty += lstOldOrder[Oindex].qty; // Increase Quantity in newOrderItem
lstOldOrder.splice(Oindex, 1); // Delete that Item from OldArray
}
mergedOrderList.push(newOrder); // Add the Item in Merged
});
mergedOrderList.concat(lstOldOrder); // Finally add all the remaining Items
All the edge cases in the code are not handled properly sorry for that.
Feel free to edit my answer, it may help someone else

Multiselect returns only one option

im trying to get the options selected but im getting only the last selected option from the select input..
state never gets updated to multiple options..just the last option ,ive tried many options but nothing is saving the multile options.
currentPage: 3,
custFirstname: "",
custLastName: "",
custPhoneNum: "",
custEmail: "",
vehicleNum: "",
vehicleMake: "",
vehicleModel: "",
defects_tank: "",
defects_tankLogo: "",
defects_lightglass: "",
defects_seatcover: "",
defects_crashgaurd: "",
defects_mirrors: "",
defects_indicators: "",
electricals_headlight: "y",
electricals_tailLight: "y",
electricals_console: "y",
electricals_indicatorF: "y",
electricals_indicatorR: "y",
electricals_horn: "y",
petrolLevel: "",
battery: "",
jobs: [],
job: {
description: "",
repObserv: "",
customerReq: "",
typeOfService: "",
charges: "",
services: []
}
};
im updating the state -> job -> services
handleJobsDropDown = e => {
console.log(e.target.options);
const { options } = e.target;
const value = [];
for (let i = 0, l = options.length; i < l; i++) {
if (options[i].selected) {
value.push(options[i].value);
}
}
this.setState({
job: { ...this.state.job, services: value }
});
};
<select
multiple={true}
value={this.state.job.services}
onChange={this.handleJobsDropDown}
>
<option value="paid">Paid Serv</option>
<option value="free">Free Serv</option>
<option value="chain">Chain Serv</option>
<option value="repeat">Rpt Serv</option>
</select>

Reading from a text file in swift and dealing with white space

I'm learning Swift and I'd just like to know the best way to go about reading in a text file, breaking it up into lines and then taking each word on each line and turn the words into strings that can be loaded into class initialisers.
For example, if I have this text file:
**This is just a random text file, and the text on this line
and this line is not needed**
birth year birth month birth day favourite colour
1990 11 12 red
1995 2 4 pink
1992 5 3 orange
1987 3 19 blue
I want to take the birth year, birth month, birth day and favourite colour from each line and then load it into a class like this:
Person(birthYear: 1990, birthMonth: 11, birthDay: 12, favouriteColour: red)
The text file that I want to read in might have an uneven amount of spaces so the output will look like this (for the given text file):
["**This", "is", "just", "a", "random", "text", "file,", "and", "the", "text", "on", "this", "line"]
["and", "this", "line", "is", "not", "needed**"]
["birth", "year", "", "", "", "birth", "month", "", "", "birth", "day", "", "", "", "", "favourite", "colour"]
["1990", "", "", "", "", "", "", "", "", "", "11", "", "", "", "", "", "", "", "", "", "", "", "12", "", "", "", "", "", "", "", "", "", "", "", "red"]
["1995", "", "", "", "", "", "", "", "", "", "", "2", "", "", "", "", "", "", "", "", "", "", "", "", "4", "", "", "", "", "", "", "", "", "", "", "", "pink", ""]
["1992", "", "", "", "", "", "", "", "", "", "", "5", "", "", "", "", "", "", "", "", "", "", "", "", "3", "", "", "", "", "", "", "", "", "", "", "", "orange"]
["1987", "", "", "", "", "", "", "", "", "", "", "3", "", "", "", "", "", "", "", "", "", "", "", "19", "", "", "", "", "", "", "", "", "", "", "", "blue"]
Here is my code so far:
let path = "path to my file"
if let contents = try? String(contentsOfFile: path) {
// breaking the text file up into lines
let lines = contents.components(separatedBy: "\n")
// breaking the lines up into wordsw
for line in lines {
let elements = line.components(separatedBy: " ")
print(elements)
}
}
I'm just wondering what the best way to deal with white space in these cases would be. Thank you in advance for your replies.
You can use a simple solution to clean all Tabs and Double spaces. Try use this piece of code.
func cleanTabsAndSpace(in text:String) -> String {
var newText = text
newText = newText.filter{ $0 != "\t" }.reduce(""){ str, char in
if let lastChar = str.last, lastChar == " " && lastChar == char {
return str
}
return str + String(char)
}
return newText.trimmingCharacters(in: .whitespacesAndNewlines)
}
After create this function you can call it inside your function
if let contents = try? String(contentsOfFile: path) {
// Clean undesired chars
let cleanContent = cleanTabsAndSpace(in: contents)
// breaking the text file up into lines
let lines = cleanContent.components(separatedBy: "\n")
// breaking the lines up into wordsw
for line in lines {
let elements = line.components(separatedBy: " ")
print(elements)
}
}
With this you will have all your content separated as you wish. Now you have just to follow as you want, parsing the content as you want and create your objects.
I'm just considering this structure you described in your question.
Good luck friend and Feel free to contact me if you need something more.
There is a split(separator:maxSplits:omittingEmptySubsequences:)
method which allows to split a String
into an array of SubStrings.
In contrast to components(separatedBy:) this method (by default)
omits empty substrings caused by consecutive separator characters.
Example:
let line = "1990 11 12 red"
let elements = line.split(separator: " ")
print(elements) // ["1990", "11", "12", "red"]
Here element has the type [SubString], i.e. the substrings reference
the original character storage in line, without duplicating it.
If you need "real" strings, then change it to
let elements = line.split(separator: " ").map(String.init)
Applied to your case:
if let contents = try? String(contentsOfFile: path) {
let lines = contents.components(separatedBy: "\n")
for line in lines {
let elements = line.split(separator: " ")
print(elements)
}
}

Resources