Scala 基于字段值的筛选器集合

Scala 基于字段值的筛选器集合,scala,Scala,我有这个收藏 class ConvEntry(designation: String, saeThick: Double, common: Boolean) val convList = immutable.List( new ConvEntry("16 Gauge", 0.0598, true), new ConvEntry("1/16th Inch", 0.0625, true), new ConvEntry("15 Gauge", 0.0673, fal

我有这个收藏

class ConvEntry(designation: String, saeThick: Double, common: Boolean)
val convList = immutable.List(
      new ConvEntry("16 Gauge", 0.0598, true),
      new ConvEntry("1/16th Inch", 0.0625, true),
      new ConvEntry("15 Gauge", 0.0673, false),
      new ConvEntry("14 Gauge", 0.0747, false),
      new ConvEntry("13 Gauge", 0.0897, false),
      new ConvEntry("12 Gauge", 0.1046, true),
      new ConvEntry("11 Gauge", 0.1196, false),
      new ConvEntry("1/8th Inch", 0.1250, true),
      new ConvEntry("10 Gauge", 0.1345, false),
      new ConvEntry("0.160 Inch", 0.1600, false),
      new ConvEntry("8 Gauge", 0.1644, false),
      new ConvEntry("3/16th Inch", 0.1875, true),
      new ConvEntry("0.190 Inch", 0.1900, false),
      new ConvEntry("0.204 Inch", 0.2040, false),
      new ConvEntry("1/4 Inch", 0.2500, true),
      new ConvEntry("5/16th Inch", 0.3125, true),
      new ConvEntry("3/8th Inch", 0.3750, true),
      new ConvEntry("7/16th Inch", 0.4375, true),
      new ConvEntry("1/2 Inch", 0.5000, true),
      new ConvEntry("9/16th Inch", 0.5625, true),
      new ConvEntry("5/8th Inch", 0.6250, true),
      new ConvEntry("11/16th Inch", 0.6875, true),
      new ConvEntry("3/4th Inch", 0.7500, true),
      new ConvEntry("13/16th Inch", 0.8125, true),
      new ConvEntry("7/8 Inch", 0.8750, true),
      new ConvEntry("1 Inch", 1.0000, true),
      new ConvEntry("1 1/4 Inch", 1.2500, true),
      new ConvEntry("1 1/2 Inch", 1.5000, true),
      new ConvEntry("1 3/4 Inch", 1.7500, true),
      new ConvEntry("2 Inch", 2.0000, true),
      new ConvEntry("2 1/2 Inch", 2.5000, true)
)
我想知道的是如何根据字段中的各种值过滤集合。我需要一个基于真值列表的算法,一个假值列表,以及一个我需要在给定数字的正上方和下方找到条目的算法


对于集合,这是可能的,还是我需要使用老式的暴力循环方法。

对于真值或假值的集合:

Collection[ConvEntry]
上有一个过滤函数,它将函数从
ConvEntry
转换为
Boolean
,过滤函数的输出将是一个
Collection[ConvEntry]
,其中包含函数返回true的项

例如,对于真正的条目:

val filteredList = convList.filter(_.common)
val filteredList = convList.filterNot(_.common)
及虚假记项:

val filteredList = convList.filter(_.common)
val filteredList = convList.filterNot(_.common)
对于项目前后的元素,可以使用带有检查值的函数的
indexWhere
,然后使用index-1和index+1获取上一个和下一个项目。这是假设“上一个”和“下一个”是指根据列表已经存在的顺序。虽然使用Boris建议的二进制搜索,但评论中的蜘蛛会更有效


请注意,如果要按索引访问项目,则使用
向量可能更合适。有关各种集合类型的性能特征的描述,请参阅。

对于此用例,使用分区比使用过滤器要好:

val (commonConvs, uncommonConvs) = convList.partition(_.common)
下面的函数表面上有点复杂,但这意味着您只需要遍历列表一次(如果使用
indexWhere
,则需要遍历3次)。所以是O(N)

注:3个结果属于类型
Option[ConvEntry]
,因为不保证任何3个值实际存在


这是最佳情况O(N),因为它使用的是
foldLeft
,但如果使用while循环,则可以得到最佳情况O(1)。您也可以使用尾部递归,但是循环通常要快一点。

对于真值和假值,您可以使用
分区

val(trueValues,falseValues)=convList.partition(u.common)

对于接近某个值的值,可能需要将序列转换为树集。另外,将您的类作为案例类处理更方便

import scala.collection.immutable.TreeSet
case class ConvEntry(designation: String, saeThick: Double, common: Boolean)

val convList = List(
      ConvEntry("16 Gauge", 0.0598, true),
        // the rest of your list goes here ...
      ConvEntry("2 1/2 Inch", 2.5000, true)
)

val myOrdering = Ordering.fromLessThan[ConvEntry]{(x,y) => x.saeThick < y.saeThick}
val ts = TreeSet.empty(myOrdering) ++ convList

def beforeAndAfter(saeThick:Double, ts:TreeSet[ConvEntry]) = {
    (for (item<-ts.find(_.saeThick==saeThick)) yield {
      (ts.to(item).take(1) ++ ts.from(item).take(2)).toList
    }).getOrElse(List[ConvEntry]())
}

scala> beforeAndAfter(0.204, ts)
res12: List[ConvEntry]] = List(ConvEntry(16 Gauge,0.0598,true), ConvEntry(0.204 Inch,0.204,false), ConvEntry(1/4 Inch,0.25,true))

scala> beforeAndAfter(0.625, ts)
List[ConvEntry] = List(ConvEntry(16 Gauge,0.0598,true), ConvEntry(5/8th Inch,0.625,true), ConvEntry(11/16th Inch,0.6875,true))
导入scala.collection.immutable.TreeSet
case类ConvEntry(名称:String,saeThick:Double,common:Boolean)
val convList=列表(
修道院(“16号”,0.0598,真实),
//你名单的其他部分在这里。。。
修道院(“2 1/2英寸”,2.5000,真实)
)
val myOrdering=排序。从小于[ConvEntry]{(x,y)=>x.saeThick前后(0.625,ts)
列表[ConvEntry]=列表(ConvEntry(16号仪表,0.0598,正确)、ConvEntry(5/8英寸,0.625,正确)、ConvEntry(11/16英寸,0.6875,正确))

谢谢大家。我听取了大家的一些建议。以下是我的结论,我仍在编写单元测试以确保它正常工作

trait Converter {

  val pointTwo = (ret: Double) => BigDecimal(ret).setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble
  val pointFour = (ret: Double) => BigDecimal(ret).setScale(4, BigDecimal.RoundingMode.HALF_UP).toDouble

  val convList = immutable.List[ConvEntry](
    new ConvEntry("16 Gauge", 0.0598, true),
    new ConvEntry("1/16th Inch", 0.0625, true),
    new ConvEntry("15 Gauge", 0.0673, false),
    new ConvEntry("14 Gauge", 0.0747, false),
    new ConvEntry("13 Gauge", 0.0897, false),
    new ConvEntry("12 Gauge", 0.1046, true),
    new ConvEntry("11 Gauge", 0.1196, false),
    new ConvEntry("1/8th Inch", 0.1250, true),
    new ConvEntry("10 Gauge", 0.1345, false),
    new ConvEntry("0.160 Inch", 0.1600, false),
    new ConvEntry("8 Gauge", 0.1644, false),
    new ConvEntry("3/16th Inch", 0.1875, true),
    new ConvEntry("0.190 Inch", 0.1900, false),
    new ConvEntry("0.204 Inch", 0.2040, false),
    new ConvEntry("1/4 Inch", 0.2500, true),
    new ConvEntry("5/16th Inch", 0.3125, true),
    new ConvEntry("3/8th Inch", 0.3750, true),
    new ConvEntry("7/16th Inch", 0.4375, true),
    new ConvEntry("1/2 Inch", 0.5000, true),
    new ConvEntry("9/16th Inch", 0.5625, true),
    new ConvEntry("5/8th Inch", 0.6250, true),
    new ConvEntry("11/16th Inch", 0.6875, true),
    new ConvEntry("3/4th Inch", 0.7500, true),
    new ConvEntry("13/16th Inch", 0.8125, true),
    new ConvEntry("7/8 Inch", 0.8750, true),
    new ConvEntry("1 Inch", 1.0000, true),
    new ConvEntry("1 1/4 Inch", 1.2500, true),
    new ConvEntry("1 1/2 Inch", 1.5000, true),
    new ConvEntry("1 3/4 Inch", 1.7500, true),
    new ConvEntry("2 Inch", 2.0000, true),
    new ConvEntry("2 1/2 Inch", 2.5000, true)
  )

  def resolveDesignation(intake: Double, commonParam: Boolean, round: Rounder): ConvEntry = {
    val tpl = loopSearch(convList.filter {_.common == commonParam }, intake)
    matchRound(intake, tpl, round)
  }

  def matchRound(target: Double, x: (ConvEntry, ConvEntry), round: Rounder): ConvEntry = round match {
    case Rounder.Up => x._2
    case Rounder.Down => x._1
    case Rounder.Closest if (target - x._1.saeThick) < (x._2.saeThick - target ) =>  x._1
    case Rounder.Closest if (target - x._1.saeThick) >= (x._2.saeThick - target ) =>  x._2
  }

  def loopSearch(list: List[ConvEntry], target: Double): (ConvEntry, ConvEntry) = {
    var prev: ConvEntry = null

    list.foreach { x =>
      if (x.saeThick == target) return (null, x)
      else if (x.saeThick > target) return (prev, x)
      else prev = x
    }
    (null, null)
  }
}
trait转换器{
val pointTwo=(ret:Double)=>BigDecimal(ret).setScale(2,BigDecimal.RoundingMode.HALF_UP).toDouble
val pointFour=(ret:Double)=>BigDecimal(ret).setScale(4,BigDecimal.RoundingMode.HALF_UP).toDouble
val convList=不可变。列表[召集人](
新修道院(“16号”,0.0598,真实),
新修道院(“1/16英寸”,0.0625,真实),
新修道院(“15号”,0.0673,假),
新修道院(“14号仪表”,0.0747,假),
新修道院(“13号”,0.0897,假),
新修道院(“12轨距”,0.1046,真实),
新修道院(“11号量规”,0.1196,假),
新修道院(“1/8英寸”,0.1250,真实),
新修道院(“10号仪表”,0.1345,假),
新修道院(“0.160英寸”,0.1600,假),
新修道院(“8号量规”,0.1644,假),
新修道院(“3/16英寸”,0.1875,真实),
新修道院(“0.190英寸”,0.1900,假),
新修道院(“0.204英寸”,0.2040,假),
新修道院(“1/4英寸”,0.2500,真实),
新修道院(“5/16英寸”,0.3125,真实),
新修道院(“3/8英寸”,0.3750,真实),
新修道院(“7/16英寸”,0.4375,真实),
新修道院(“1/2英寸”,0.5000,真实),
新修道院(“9/16英寸”,0.5625,真实),
新修道院(“5/8英寸”,0.6250,真实),
新修道院(“11/16英寸”,0.6875,真实),
新修道院(“3/4英寸”,0.7500,真实),
新修道院(“13/16英寸”,0.8125,真实),
新修道院(“7/8英寸”,0.8750,真实),
新修道院(“1英寸”,1.0000,真实),
新修道院(“1 1/4英寸”,1.2500,真实),
新修道院(“1 1/2英寸”,1.5000,真实),
新修道院(“1 3/4英寸”,1.7500,真实),
新修道院(“2英寸”,2.0000,真实),
新修道院(“2 1/2英寸”,2.5000,真实)
)
def resolveDesignation(入口:双精度,commonParam:Boolean,圆形:圆形):ConvEntry={
val tpl=loopSearch(convList.filter{{uu.common==commonParam},摄入)
匹配轮(进气、tpl、圆形)
}
def matchRound(目标:双,x:(召集,召集),round:Rounder):召集=轮匹配{
案例取整器向上=>x.\u 2
外壳圆形向下=>x.\u 1
案例圆形。最近if(目标-x.\U 1.saeThick)<(x.\U 2.saeThick-target)=>x.\U 1
案例圆形。最近if(目标-x.\U 1.saeThick)>=(x.\U 2.saeThick-target)=>x.\U 2
}
def loopSearch(列表:列表[ConvEntry],目标:双):(ConvEntry,ConvEntry)={
var-prev:ConvEntry=null
list.foreach{x=>
if(x.saeThick==target)返回(null,x)
否则如果(x.saeThick>target)返回(上一个,x)
else prev=x
}
(空,空)
}
}

我不太明白这个问题。在第一种情况下,
partition
w