How to modify an item in a list? - list

I'm a bit confused how to modify an item in a list. This is my structure:
type alias Player =
{ id : Int
, name : String
, isActive : Bool
}
type alias Model =
{ players : List Player
, newPlayer : Player
}
So I have a list of Players, and I want to edit a specific Player in the list (for example changing Player with Id = 2 field "isActive" to True). How could I go about this?

As a helper, you can consider using List.Extra.updateIf
newPlayers = players
|> List.Extra.updateIf (\player -> player.id == 2) (\player -> { player | isActive = True })

One solution is to use List.map:
setIsActiveForPlayer : List Player -> Int -> Bool -> List Player
setIsActiveForPlayer players id isActive =
let
update player =
if player.id == id then
{ player | isActive = isActive }
else
player
in
players |> List.map update
Another solution performs the iteration “by hand”:
setIsActiveForPlayer : List Player -> Int -> Bool -> List Player
setIsActiveForPlayer players id isActive =
case players of
[] ->
[]
player :: rest ->
if player.id == id then
{ player | isActive = isActive } :: rest
else
player :: setActivePlayer rest id isActive
This should be slightly more efficient because it reuses the tail of the list following the updated player.

Related

Clickable activities list Kotlin

I'm retrieving data to list and I need to make 2 different intents. "Activities" needs to start "e" intent and rest starts "i" intent.
class MyAdapter(private val context : Activity, private val arrayList : ArrayList<Person>) : ArrayAdapter<Person>(context,
R.layout.list_item, arrayList) {
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val inflater : LayoutInflater = LayoutInflater.from(context)
val view : View = inflater.inflate(R.layout.list_item, null)
val imageView : ImageView = view.findViewById(R.id.profile_pic)
val activities : TextView = view.findViewById(R.id.activity_name)
val person_name : TextView = view.findViewById(R.id.name_list)
val activity_time : TextView = view.findViewById(R.id.time)
val checkbox : ImageView = view.findViewById(R.id.checkbox)
val person_icon : ImageView = view.findViewById(R.id.person_icon)
imageView.setImageResource(arrayList[position].imageID)
activities.text = arrayList[position].activities
person_name.text = arrayList[position].name
activity_time.text = arrayList[position].activityTime
checkbox.setImageResource(arrayList[position].checkbox)
person_icon.setImageResource(arrayList[position].person_icon)
return view
}
}
binding.listview.adapter = MyAdapter(this, personArrayList)
binding.listview.isClickable = true
binding.listview.setOnItemClickListener { parent, view, position, id ->
val name = name[position]
val activities = activities[position]
val activityTime = activityTime[position]
val description = description[position]
val imageID = imageID[position]
val i = Intent(this, DescriptionActivity::class.java)
val e = Intent(this, ProfileScreen::class.java)
i.putExtra("name", name)
i.putExtra("activityTime", activityTime)
e.putExtra("activities", activities)
i.putExtra("imageID", imageID)`your text`
i.putExtra("description", description)
startActivity(i)
}
startActivity (e) overrides startActivity(i)
and making activities OnClickListener crashes the app.

Adding two types of object to mutableListOf<MyInterface>()

interface ListItem {
val style: ItemStyle
val identifier: ListItemIdentifier?
}
val mutableList = mutableListOf<ListItem>()
I have a list that I map to objects and group:
dataList.groupBy { it.type }.forEach { (type, itemList) ->
val type = TypeHeader(name = type.name )
val items = itemList.map { item ->
Item(
title = item.title,
subtitle = item.subtitle
)
}
mutableList.addAll(listOf(type , items ))
}
I need to add that objects to my mutableList but when I try
mutableList.addAll(listOf(type , items ))
there is a error
Type mismatch.
Required:
Collection<ListItem>
Found:
List<Any>
when I try cast listOf as ListItem app crashes
After some discussion in comments we got to the solution.
The problem is in this listOf() line. You try to mix type, which is a single item and items which is a list of items. listOf() does not magically flatten this to e.g.: [header, item, item, item]. It will create something like this instead: [header, [item, item, item]]. This is inferred to the list of Any objects, because some items are single objects and some are lists.
You can flatten header and items to a single list with:
listOf(header) + items
But in this case it is better to just add to mutableList twice:
mutableList.add(type)
mutableList.addAll(items)

In SwiftUI creating buttons as per different cases

I have swiftUI scene for Error.
That error can be uses for Network , login etc anything.
Buttons and their actions on that screen varies as per the errortype.
enum ErrorItem: String {
case subscriptionError = "Subscription"
case networkError = "NetworkError"
}
init(errorType: ErrorItem) {
super.init()
if errorType == ErrorItem.subscriptionError {
titleString = "Login Error"
numOfButton = 1 // I do not want to use this . I want to create some closure and enum of buttons and create array of buttons
}
else {
titleString = "Something Went Wrong"
numOfButton = 2
}
}
I am handling number of buttons display by "numofButtons".
But for each case number of buttons, their titles and their actions will also be different.
What are the best approach to handle that ?
Can i create something like this and have array of ErrorButtonTypes. So if one screen contain 2 buttons i.e close and action button i can use both and if one screen contain 1button only close button i can use only 1 button
enum ErrorButtonType {
case close(String) // String = title
case action(String, (() -> Void) // String = title, function = action to take with that button
}
The easy and efficient way to declare var inside the enum and set value for each case. Like this
enum ErrorItem: String {
case subscriptionError = "Subscription"
case networkError = "NetworkError"
var title: String {
switch self {
case .subscriptionError:
return "Login Error"
case .networkError:
return "Something Went Wrong"
}
}
var numOfButton: Int {
switch self {
case .subscriptionError:
return 1
case .networkError:
return 2
}
}
}
And your init is
init(errorType: ErrorItem) {
super.init()
titleString = errorType.title
numOfButton = errorType.numOfButton
}
EDIT
As per your edited question, you can use enum with action like this.
Your enum
enum ErrorButtonType {
case close(String) // String = title
case action(String, (() -> Void)) // String = title, function = action to take with that button
}
Declare your enum
var errorType: ErrorButtonType = ErrorButtonType.close("Close")
set enum value
let action: (() -> Void) = {
// Your button action
}
errorType = ErrorButtonType.action("Action", action)
Get enum value
switch errorType {
case .close(let title):
print(title)
case .action(let title, let action):
print(title)
action() // Assign this action to button
}

Swift 3 - NSOutlineView with expandable items

i would like to realize an outlineView, which shows string values as root values. the following code works for me:
import Cocoa
class TestController: NSViewController, NSOutlineViewDataSource, NSOutlineViewDelegate {
#IBOutlet weak var outlineView: NSOutlineView!
var items: [String] = ["Item 1", "Item 2", "Item 3", "Item 4","Item 5"]
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
return items[index]
}
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
return true
}
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
if item == nil {
return items.count
}
return 0
}
func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
let v = outlineView.make(withIdentifier: "HeaderCell", owner: self) as! NSTableCellView
if let tf = v.textField {
tf.stringValue = item as! String
}
return v
}
}
This is the result:
but i don't know, how i can assign different string values for Item 1 (for example). i wish to realize something like that:
+Item 1
++Sub Item 1.1
++Sub Item 1.2
+Item 2
++Sub Item 2.1
+Item 3
++Sub Item 3.1
++Sub Item 3.2
++Sub Item 3.3
...
can somebody help me?
A simple String array will not be too much of use here, you need a dictionary at least to display sub items. I would recommend to introduce a little helper model, lets call it Item. It holds a name, and a number of children Items, those will be the sub-items.
struct Item {
let name: String
var childrens: [Item] = []
/// Create a helper function to recursivly create items
///
/// - Parameters:
/// - parents: number of parent items
/// - childrens: number of children for each parent item
/// - Returns: array of Item
static func itemsForNumberOf(parents: Int, childrens: Int) -> [Item] {
var items: [Item] = []
for parentID in 1...parents {
var parent = Item(name: "Index \(parentID)",childrens: [])
for childrenID in 1...childrens {
let children = Item(name: "Index \(parentID).\(childrenID)",childrens: [])
parent.childrens.append(children)
}
items.append(parent)
}
return items
}
}
Declare a property on your viewController called items, and return some Item's using the itemsForNumberOf helper function.
class TestController: NSViewController, NSOutlineViewDataSource, NSOutlineViewDelegate {
let items: [Item] = {
return Item.itemsForNumberOf(parents: 5, childrens: 3)
}()
#IBOutlet weak var outlineView: NSOutlineView!
}
In TestController override the viewDidLoad() function and assign the delegate and datasource to your viewController.
override func viewDidLoad() {
super.viewDidLoad()
self.outlineView.delegate = self
self.outlineView.dataSource = self
}
Check the documentation of NSOutlineViewDataSource and in specific this API
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
if item == nil {
return items[index]
}
if let item = item as? Item, item.childrens.count > index {
return item.childrens[index]
}
return ""
}
Return expandalbe property based on children of the received Item.
If it is empty, no children -> not expandable
If it is not empty, has children -> expandable
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
guard let item = item as? Item else {
return false
}
return !item.childrens.isEmpty
}
Same for returning the sub items count by using childrens property again
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
if item == nil {
return items.count
}
if let item = item as? Item {
return item.childrens.count
}
return 0
}
In your viewFor function, you need to make sure to return nil to everything, what is not a Item type asking for a view.
func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
guard let item = item as? Item else {
return nil
}
let v = outlineView.make(withIdentifier: "HeaderCell", owner: self) as! NSTableCellView
if let tf = v.textField {
tf.stringValue = item.name
}
return v
}
}
And you should end up with something like this:
If you want to display hierarchical data, the data can't be a simple array of strings. Instead of item strings, use dictionaries or custom objects which have title/name and children properties. The children property is an array of child items.
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any returns the children of item. If item is "Item 1" and index is 1, the return value is "Sub Item 1.2".
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int returns the number of children of ``. If item is "Item 1" , the return value is 2.

List of Records in F#?

How do you work with a List of Records in F#? How would you even pass that as an argument in a function? I want to do something like this:
type Car = {
Color : string;
Make : string;
}
let getRedCars cars =
List.filter (fun x -> x.Color = "red") cars;
let car1 = { Color = "red"; Make = "Toyota"; }
let car2 = { Color = "black"; Make = "Ford"; }
let cars = [ car1; car2; ]
I need a way to tell my function that "cars" is a List of Car records.
Your code works just fine. It can also be written:
let getRedCars cars =
List.filter (function {Color = "red"} -> true | _ -> false) cars
If you're ever concerned the wrong signature is being inferred, you can add type annotations. For example:
let getRedCars (cars:Car list) : Car list = //...