knoxgon
knoxgon

Reputation: 1243

How to replace nth element of a Seq with another Seq element?

Let's assume we have the following list of items.

val utils: Seq[Utilities] = {
  Seq(
    Utilities("jackhammer", 24, "Industrial item", "For sale", "Available"),
    Utilities("axe",        19, "Home item",       "For sale", "Available"),
    Utilities("pick",       39, "Garage item",     "For sale", "Not Available")
  )
}

The skeleton class for Utilities is as follows:

final case class Utilities(item_name: String, ref_id: Int, 
                           item_type: String, sale_status: String, status: String)

And we also have another list of items of the current sale status of Utilities: (The class does not have any relation with Utilities, we only aim to apply its 2nd column into Utilities.)

val newAttr: Seq[NewAttributes] = {
      Seq(
        NewAttributes(1,  "For sale"),
        NewAttributes(3,  "Not for sale"),
        NewAttributes(18, "Discontinued")
      )
    }

The skeleton class for NewAttributes is as follows:

final case class NewAttributes(r_id: Int, status: String)

How can I replace Utilities' sale_status record with the NewAttributes status in order?

With the new update, Utilities shall be like:

Utilities("jackhammer", 24, "Industrial item", "For sale",     "Available")
Utilities("axe",        19, "Home item",   "Not for sale", "Available")
Utilities("pick",       39, "Garage item", "Discontinued", "Not Available")

I'm successfully retrieving the elements from newAttr with the following code, but I've no idea how to apply them to utils to achieve the above schema.

val prepStatuses = 
   for(na <- newAttr)
      yield na.status

Any help is greatly appreciated!

Upvotes: 0

Views: 324

Answers (4)

Ramesh Maharjan
Ramesh Maharjan

Reputation: 41987

You can achieve your requirement by using zipWithIndex

val zippedNewAttr = newAttr.zipWithIndex.map(_.swap).toMap
val result = for(x <- utils.zipWithIndex; y = zippedNewAttr(x._2))yield Utilities(x._1.item_name, x._1.ref_id, x._1.item_name, y.status, x._1.status)

Explanation:
zipWithIndex generates a Tuple2 where the first value is the original value and the second value is the index of each value. for example newAttr.zipWithIndex will produce

  (NewAttributes(1, "For sale"),1)
  (NewAttributes(3, "Not for sale"),2)
  (NewAttributes(18, "Discontinued"),3)

_.swap swaps the above generated tuple2 values and .toMap generates map for each Tuple2 records so zippedNewAttr is

  (1 -> NewAttributes(1, "For sale"))
  (2 -> NewAttributes(3, "Not for sale"))
  (3 -> NewAttributes(18, "Discontinued"))

The for loop generates Utilities object again but with the replaced Utilities sale_status record with the NewAttributes status and zipWithIndex preserves the order.

Updated

There is another better approach using iterators

val utilsIterator = utils.iterator
val newAttrIterator = newAttr.iterator

val result = ArrayBuffer.empty[Utilities]
while(utilsIterator.hasNext && newAttrIterator.hasNext){
  val utils = utilsIterator.next()
  val newAttr = newAttrIterator.next()
  result.append(Utilities(utils.item_name, utils.ref_id, utils.item_type, newAttr.status, utils.status))
}

result is the required output

Upvotes: 0

Leo C
Leo C

Reputation: 22449

You can simply map each index of utils to a copy of the corresponding utils element with modified sale_status:

utils.indices.map(i => utils(i).copy(sale_status = newAttr(i).status))

Upvotes: 0

Robin Green
Robin Green

Reputation: 33103

You need a way to find the data you need:

def findStatus(id: Int): Option[String] = 
  newAttr.find(_.r_id == id).map(_.status)

And then you need to use that in a for comprehension:

val mappedUtils = for(u <- utils)
  yield u.copy(sale_status = findStatus(u.ref_id).getOrElse(sys.error(s"No such id ${u.ref_id}")))

Upvotes: 1

rincewind
rincewind

Reputation: 623

If the order is correct it is straight forward:

  final case class Utilities(item_name: String, ref_id: Int, item_type: String, sale_status: String, status: String)
  val utils: Seq[Utilities] = {
    Seq(
      Utilities("jackhammer", 24, "Industrial item", "For sale", "Available"),
      Utilities("axe", 19, "Home item", "For sale", "Available"),
      Utilities("pick", 39, "Garage item", "For sale", "Not Available")
    )
  }

  final case class NewAttributes(r_id: Int, status: String)
  val newAttr: Seq[NewAttributes] = {
    Seq(
      NewAttributes(1, "For sale"),
      NewAttributes(3, "Not for sale"),
      NewAttributes(18, "Discontinued")
    )
  }

  utils.zip(newAttr).map{ case(utility, newAttribute) =>
      utility.copy(sale_status = newAttribute.status)
  }

Upvotes: 2

Related Questions