Related
In Raku, how does one write the equivalent of Haskell's span function?
In Haskell, given a predicate and a list, one can split the list into two parts:
the longest prefix of elements satisfying the predicate
the remainder of the list
For example, the Haskell expression …
span (< 10) [2, 2, 2, 5, 5, 7, 13, 9, 6, 2, 20, 4]
… evaluates to …
([2,2,2,5,5,7],[13,9,6,2,20,4])
How does one write the Raku equivalent of Haskell's span function?
Update 1
Based on the answer of #chenyf, I developed the following span subroutine (additional later update reflects negated predicate within span required to remain faithful to the positive logic of Haskell's span function) …
sub span( &predicate, #numberList )
{
my &negatedPredicate = { ! &predicate($^x) } ;
my $idx = #numberList.first(&negatedPredicate):k ;
my #lst is Array[List] = #numberList[0..$idx-1], #numberList[$idx..*] ;
#lst ;
} # end sub span
sub MAIN()
{
my &myPredicate = { $_ <= 10 } ;
my #myNumberList is Array[Int] = [2, 2, 2, 5, 5, 7, 13, 9, 6, 2, 20, 4] ;
my #result is Array[List] = span( &myPredicate, #myNumberList ) ;
say '#result is ...' ;
say #result ;
say '#result[0] is ...' ;
say #result[0] ;
say #result[0].WHAT ;
say '#result[1] is ...' ;
say #result[1] ;
say #result[1].WHAT ;
} # end sub MAIN
Program output is …
#result is ...
[(2 2 2 5 5 7) (13 9 6 2 20 4)]
#result[0] is ...
(2 2 2 5 5 7)
(List)
#result[1] is ...
(13 9 6 2 20 4)
(List)
Update 2
Utilizing information posted to StackOverflow concerning Raku's Nil, the following updated draft of subroutine span is …
sub span( &predicate, #numberList )
{
my &negatedPredicate = { ! &predicate($^x) } ;
my $idx = #numberList.first( &negatedPredicate ):k ;
if Nil ~~ any($idx) { $idx = #numberList.elems ; }
my List $returnList = (#numberList[0..$idx-1], #numberList[$idx..*]) ;
$returnList ;
} # end sub span
sub MAIN()
{
say span( { $_ == 0 }, [2, 2, 5, 7, 4, 0] ) ; # (() (2 2 5 7 4 0))
say span( { $_ < 6 }, (2, 2, 5, 7, 4, 0) ) ; # ((2 2 5) (7 4 0))
say span( { $_ != 9 }, [2, 2, 5, 7, 4, 0] ) ; # ((2 2 5 7 4 0) ())
} # end sub MAIN
I use first method and :k adverb, like this:
my #num = [2, 2, 2, 5, 5, 7, 13, 9, 6, 2, 20, 4];
my $idx = #num.first(* > 10):k;
#num[0..$idx-1], #num[$idx..*];
A completely naive take on this:
sub split_on(#arr, &pred) {
my #arr1;
my #arr2 = #arr;
loop {
if not &pred(#arr2.first) {
last;
}
push #arr1: #arr2.shift
}
(#arr1, #arr2);
}
Create a new #arr1 and copy the array into #arr2. Loop, and if the predicate is not met for the first element in the array, it's the last time through. Otherwise, shift the first element off from #arr2 and push it onto #arr1.
When testing this:
my #a = [2, 2, 2, 5, 5, 7, 13, 9, 6, 2, 20, 4];
my #b = split_on #a, -> $x { $x < 10 };
say #b;
The output is:
[[2 2 2 5 5 7] [13 9 6 2 20 4]]
Only problem here is... what if the predicate isn't met? Well, let's check if the list is empty or the predicate isn't met to terminate the loop.
sub split_on(#arr, &pred) {
my #arr1;
my #arr2 = #arr;
loop {
if !#arr2 || not &pred(#arr2.first) {
last;
}
push #arr1: #arr2.shift;
}
(#arr1, #arr2);
}
So I figured I'd throw my version in because I thought that classify could be helpful :
sub span( &predicate, #list ) {
#list
.classify({
state $f = True;
$f &&= &predicate($_);
$f.Int;
}){1,0}
.map( {$_ // []} )
}
The map at the end is to handle the situation where either the predicate is never or always true.
In his presentation 105 C++ Algorithms in 1 line* of Raku (*each) Daniel Sockwell discusses a function that almost answers your question. I've refactored it a bit to fit your question, but the changes are minor.
#| Return the index at which the list splits given a predicate.
sub partition-point(&p, #xs) {
my \zt = #xs.&{ $_ Z .skip };
my \mm = zt.map({ &p(.[0]) and !&p(.[1]) });
my \nn = mm <<&&>> #xs.keys;
return nn.first(?*)
}
#| Given a predicate p and a list xs, returns a tuple where first element is
#| longest prefix (possibly empty) of xs of elements that satisfy p and second
#| element is the remainder of the list.
sub span(&p, #xs) {
my \idx = partition-point &p, #xs;
idx.defined ?? (#xs[0..idx], #xs[idx^..*]) !! ([], #xs)
}
my #a = 2, 2, 2, 5, 5, 7, 13, 9, 6, 2, 20, 4;
say span { $_ < 10 }, #a; #=> ((2 2 2 5 5 7) (13 9 6 2 20 4))
say span { $_ < 5 }, [6, 7, 8, 1, 2, 3]; #=> ([] [6 7 8 1 2 3])
Version 6.e of raku will sport the new 'snip' function:
use v6.e;
dd (^10).snip( * < 5 );
#«((0, 1, 2, 3, 4), (5, 6, 7, 8, 9)).Seq»
How do I:
Identify which item from the dataframe df falls within each list (list1 or list2)
Create a new column ('new_item')
Determine which variable should be appended to the 'item' value and add it to the new column
Two lists of unique items:
list1 = ['one','two','shoes']
list2 = ['door','four','tires']
If item is in list1, append the following variable value to the end of the item and append it to the 'new_item' column:
twentysix_above = '_26+' (value is equal or greater than 26)
six_to_twentyfive = '_25' (value is between 6 and 25)
one_to_five = '_5' (value is between 1 and 5)
If item is in list2, append the following variable value to the end of each item and append it to the 'new_item' column:
twentyone_above = '_21+' (value is equal or greater than 21)
one_to_twenty = '_20' (value is between 1 and 20)
If the item isn't in either list, carry over the item name to the 'new_item' column.
Dataframe column will have one, some, or none of the 'items' from each list in it and an associated number from the 'number' column. I've gotten partially there, but I'm not sure how to compare to the other list and put that all into the 'new_item' column? Any help is appreciated, thanks!
>> print df
item number
0 one 4
1 door 55
2 sun 2
3 tires 62
4 tires 7
5 water 94
>> list1 = ['one','two','shoes']
>> list2 = ['door','four','tires']
>> df['match'] = df.item.isin(list1)
>> bucket = []
>> for row in df.itertuples():
if row.match == True and row.item > 25:
bucket.append(row.item + '_26+')
elif row.match == True and row.item >5:
bucket.append(row.item + '_25')
elif row.match == True and row.item >0:
bucket.append(row.item +'_5')
else:
bucket.append(row.item)
df['new_item'] = bucket
>> print df
item number match new_item
0 one 4 True one_5
1 door 55 True door
2 sun 2 False sun
3 tires 62 True tires
4 tires 7 True tires
5 water 94 False water
Desired Result: (comparing both lists and potentially not needing the boolean check column)
item number new_item
0 one 4 one_20
1 door 55 door__21+
2 sun 2 sun
3 tires 62 tires_21
4 tires 7 tires_20
5 water 94 water
It looks like your desired result is a bit off. The first row is in list one and has a value of 4, so it should be 'one_5' right?
Anyway, this can be accomplished with boolean masking. DataFrames have a useful isin() function making it easy to find if the value is in your lists. Then you have two more conditions, if you need a value between two numbers, or just one more condition if the range is unbounded.
import pandas as pd
import numpy as np
df = pd.DataFrame({'item': ['one', 'door', 'sun', 'tires', 'tires', 'water'],
'number': [4, 55, 2, 62, 7, 94]})
list1 = ['one','two','shoes']
list2 = ['door','four','tires']
df['new_item'] = df['item']
logic1 = np.logical_and(df.item.isin(list1), df.number > 25)
logic2 = np.logical_and.reduce([df.item.isin(list1), df.number > 5, df.number <= 25])
logic3 = np.logical_and.reduce([df.item.isin(list1), df.number > 1, df.number <= 5])
logic4 = np.logical_and(df.item.isin(list2), df.number >= 21)
logic5 = np.logical_and.reduce([df.item.isin(list2), df.number > 1, df.number < 20])
df.loc[logic1,'new_item'] = df.loc[logic1,'item']+'_26+'
df.loc[logic2,'new_item'] = df.loc[logic2,'item']+'_25'
df.loc[logic3,'new_item'] = df.loc[logic3,'item']+'_5'
df.loc[logic4,'new_item'] = df.loc[logic4,'item']+'_21+'
df.loc[logic5,'new_item'] = df.loc[logic5,'item']+'_20'
And we have this as the output
Scala accessing list objects and evaluating number of cycles
I have list of objects
case class ItemDesc(a: Int, b: Int, c: Int, d: Int,e: Int, f: Int, g: Int desc: String)
val example = List(ItemDesc(6164,6165,6166,-6195,-6175,-6186,-6195, The values are correct), ItemDesc(14879,-14879,14879,-14894, 14879,14879,14894, The values are ok), ItemDesc(19682,-19690,-19682,19694,19690,19682,19694,The values are good),ItemDesc(5164,-5165,-5166,-6195,5165,5166,6195,The values are correct),ItemDesc(5879,5879,5879,5894,5879,5879,5879,The values are ok))
From the 'example' List, I want to access object 'ItemDesc'. And get the count of cycles. how many times it turns from negative to positive and stays positive for >= 2 seconds.
If >= 2 seconds it is a cycle.
Example 1: (6164,6165,6166,-6195,-6175,-6186,-6195, good)
No. of cycles is 2.
Reason: As we move from 1st element of list to 3rd element, we had 2 intervals which means 2 seconds. Interval is >= 2. So it is one cycle. As we move to 3rd element of list to 4th element, it is a negative value. So we start counting from 4th element and move to 7th element and all elements have same negative sign. we had 3 intervals which means 3 seconds. Interval is >= 2. So it is one cycle. We start counting intervals fresh from zero as one number changes from positive to negative and vice-versa.
Example 2: (14879,-14879,14879,-14894, 14879,14879,14894,better)
No. of cycles is 1.
Reason: As we move from 1st element of list to 2nd element, the sign changes to negative. So we start counting the interval from zero. From element 2 to 3, the sign changes to negative. so interval counter is zero. From element 3 to 4, the sign changes to negative. interval counter is zero. From 5th to 7th all values have same sign, we had 2 intervals which means 2 seconds. Interval is >= 2. So it is one cycle.
Example 3: (5164,-5165,-5166,-6195,5165,5166,6195,good)
No. of cycles is 2
The below code which I wrote is not giving me the no. of cycles which I am looking for. Appreciate help in fixing it.
object findCycles {
def main(args: Array[String]) {
var numberOfPositiveCycles = 0
var numberOfNegativeCycles = 0
var numberOfCycles = 0
case class itemDesc(a: Int, b: Int, c: Int, d: Int, reason: String)
val example = List(ItemDesc(6164,6165,6166,-6195,-6175,-6186,-6195, The values are correct), ItemDesc(14879,-14879,14879,-14894, 14879,14879,14894, The values are ok), ItemDesc(19682,-19690,-19682,19694,19690,19682,19694,The values are good),ItemDesc(5164,-5165,-5166,-6195,5165,5166,6195,The values are correct),ItemDesc(5879,5879,5879,5894,5879,5879,5879,The values are ok))
val data2 = example.map(x => getInteger(x)).filter(_ != "unknown").map(_.toString.toInt)
//println(data2)
var nCycle = findNCycle(data2)
println(nCycle)
}
def getInteger(obj: Any) = obj match {
case n: Int => obj
case _ => "unknown"
}
def findNCycle(obj: List[Int]) : Int = {
def NegativeCycles(fit: itemDesc): Int = {
if (fit.a < 0 && fit.b < 0 && fit.c < 0) || if( fit.b < 0 && fit.c < 0 && fit.d < 0)
{
numberOfNegativeCycles += 1
}
}
//println("negative cycle="+cycles)
def PositiveCycles(fit: itemDesc): Int = {
if (fit.a > 0 && fit.b > 0 && fit.c > 0) || if( fit.b > 0 && fit.c > 0 && fit.d > 0)
{
numberOfPositiveCycles += 1
}
}
//println("positive cycle="+cycles)
numberOfCycles = numberOfPositiveCycles + numberOfNegativeCycles
return numberOfCycles
}
}
For reference on the logic you can refer to- Number of Cycles from list of values, which are mix of positives and negatives in Spark and Scala
Ok this is rough but I think it does what you want. I'm sure there is a more elegant way to do the split method.
I haven't used your ItemDesc as its simpler to demonstrate the problem given the examples you gave.
object CountCycles extends App {
// No. of cycles is 1.
val example1 = List(1, 2, 3, 4, 5, 6, -15, -66)
// No. of cycles is 3.
val example2 = List(11, 22, 33, -25, -36, -43, 20, 25, 28)
// No. of cycles is 8
val example3 = List(1, 4, 82, 5, 6, -2, -12, -22, -32, 100, 102, 100, 102, 0, 0, -2, -12, -22, -32, 4, 82, 5, 6, -6, 8, -6, -6, 8, 8, -5, -6, -7, 9, 8, 6, -5, -6, -7)
def differentSign(x: Int, y: Int): Boolean =
(x < 0) != ( y < 0)
// return a list of sections
def split(l: List[Int]): List[List[Int]] =
l match {
case Nil ⇒ Nil
case h :: _ ⇒
val transition: Int = l.indexWhere(differentSign(h, _))
if (transition < 0) List(l)
else {
val (head, tail) = l.splitAt(transition)
head :: split(tail)
}
}
def count(l: List[Int]): Int = {
val pos: List[List[Int]] = split(l)
// count is the number of sections of length > 2
pos.count(_.length > 2)
}
println(count(example1)) // 1
println(count(example2)) // 3
println(count(example3)) // 8
}
This should be a working solution for the case where you have 7 items in the sample as shown in the description. If your case class changes and instead has a list of values then the implicit helper can be replaced with a simple call to the accessor
import scala.annotation.tailrec
import scala.language.implicitConversions
object CyclesCounter extends App {
val examples = List(
ItemDesc(6164,6165,6166,-6195,-6175,-6186,-6195, "The values are correct"),
ItemDesc(14879,-14879,14879,-14894, 14879,14879,14894, "The values are ok"),
ItemDesc(19682,-19690,-19682,19694,19690,19682,19694,"The values are good"),
ItemDesc(5164,-5165,-5166,-6195,5165,5166,6195,"The values are correct"),
ItemDesc(5879,5879,5879,5894,5879,5879,5879,"The values are ok"))
val counter = new CycleCounter
// Add the index for more readable output
examples.zipWithIndex.foreach{ case (item, index) => println(s"Item at index $index has ${counter.cycleCount(item)} cycles")}
}
class CycleCounter {
def cycleCount(item: ItemDesc): Int = {
#tailrec
def countCycles(remainingValues: List[Int], cycles: Int): Int = {
if (remainingValues.isEmpty) cycles
else {
val headItems = {
if (remainingValues.head < 0) remainingValues.takeWhile(_ < 0)
else remainingValues.takeWhile(_ >= 0)
}
val rest = remainingValues.drop(headItems.length)
if (headItems.length > 2) countCycles(rest, cycles + 1) else countCycles(rest, cycles )
}
}
countCycles(item, 0)
}
// Helper to convert ItemDesc into a List[Int] for easier processing
implicit def itemToValueList(item: ItemDesc): List[Int] = List(item.a, item.b, item.c, item.d, item.e, item.f, item.g)
}
case class ItemDesc(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int, g: Int, reason: String)
Output from running:
Item at index 0 has 2 cycles
Item at index 1 has 1 cycles
Item at index 2 has 1 cycles
Item at index 3 has 2 cycles
Item at index 4 has 1 cycles
Hope that helps
As i read, i see that your problem is to treat the case class as a single entity and no as a list of elements and a reason. I would change the case class to one of these alternatives, first one is if the amount of elements is static (4 in this case):
case class ItemDesc(a: Int, b: Int, c: Int, d: Int, reason: String) {
lazy val getAsList = List(a,b,c,d)
}
ItemDesc(1,2,3,4,"reason").getAsList
In the second case, it can be used if the amount of elements is unbounded:
case class ItemDescAlt(reason:String, elements: Int*)
ItemDescAlt("reason", 5164,-5165,-5166,-6195,5165,5166,6195)
And like the rest i will give my custom version for calculate the number of cycles:
def getCycles(list: Seq[Int]): Int = {
def headPositive(list: Seq[Int]): Boolean = {
list.headOption.forall(_ >= 0)
}
val result = list.foldLeft((0, 0, !headPositive(list))) { //we start with a symbol diferent to the firs one
case ((numberOfCycles, cycleLength, lastWasPositive), number) => { //for each element...
val numberSign = number >= 0
val actualCycleLength = if (numberSign == lastWasPositive) { //see if the actual simbol is equal to the last one
cycleLength + 1 //in that case the length is increased
} else {
0 //in the other reset it
}
val actualNCycles = if (actualCycleLength == 2) { //if the actual length is equal to to
numberOfCycles + 1 //it is a proper new cycle
} else {
numberOfCycles // no new cycles
}
(actualNCycles, actualCycleLength, numberSign) //return the actual state
}
}
result._1 //get the final number of cycles
}
If you already have a solution for List, you can convert any case class into a List using productIterator:
scala> case class X(a:Int, b:Int, c:String)
defined class X
scala> val x = X(1,2,"a")
x: X = X(1,2,a)
scala> x.productIterator.toList
res1: List[Any] = List(1, 2, a)
The main problem is that you get back a List[Any] so you might have to do more work to get a List[Int]
I have following list
List(List
(43673,38448,512,36398,1500,**BpEwv+EcDv3z**,58f39535-03b7-4e05-a2d8-3f5b424c8938),
List(302750,759,512,759,3796,**BpEwv+EcDv3v**,069865df-30c3-48c3-bf02-79f2fcff7213),
List(616278,1600,512,107418,15255,**BpEwv+EcDv3v**,b373b731-6f38-4559-808e-1c05fc06af00),
List(0,0,512,0,0,**BpEwv+EcDv3z**,24894b9f-9e30-4073-a538-186a312c670e)
)
I want to remove duplicate values marked in bold (6th index of list for all elements) from this list. The sequence of elements is fixed.
Expected output:
List(
List(43673,38448,512,36398,1500,BpEwv+EcDv3z,58f39535-03b7-4e05-a2d8-3f5b424c8938),
List(302750,759,512,759,3796,BpEwv+EcDv3v,069865df-30c3-48c3-bf02-79f2fcff7213))
How do I remove duplicate values from list using scala??
If you want to remove all occurrences of a specific value in all Lists you can use the following code:
val lss = List(List(1,2,2), List(1,2,3,4,2))
lss map (_.filter(_ != 2)) // List(List(1), List(1, 3, 4))
which removes all occurrences of 2 in all Lists.
If you want to get a single List in return you can use flatMap:
lss flatMap (_.filter(_ != 2)) // List(1, 1, 3, 4)
Based on your expected output, you can do something like
scala> val a = List(List
| (43673,38448,512,36398,1500,"BpEwv+EcDv3z","58f39535-03b7-4e05-a2d8-3f5b424c8938"),
| List(302750,759,512,759,3796,"BpEwv+EcDv3v","069865df-30c3-48c3-bf02-79f2fcff7213"),
| List(616278,1600,512,107418,15255,"BpEwv+EcDv3v","b373b731-6f38-4559-808e-1c05fc06af00"),
| List(0,0,512,0,0,"BpEwv+EcDv3z","24894b9f-9e30-4073-a538-186a312c670e")
| )
a: List[List[Any]] = List(List(43673, 38448, 512, 36398, 1500, BpEwv+EcDv3z, 58f39535-03b7-4e05-a2d8-3f5b424c8938), List(302750, 759, 512, 759, 3796, BpEwv+EcDv3v, 069865df-30c3-48c3-bf02-79f2fcff7213), List(616278, 1600, 512, 107418, 15255, BpEwv+EcDv3v, b373b731-6f38-4559-808e-1c05fc06af00), List(0, 0, 512, 0, 0, BpEwv+EcDv3z, 24894b9f-9e30-4073-a538-186a312c670e))
scala> a.groupBy(_(5)).mapValues(_(0)).map(_._2)
res0: scala.collection.immutable.Iterable[List[Any]] = List(List(302750, 759, 51
2, 759, 3796, BpEwv+EcDv3v, 069865df-30c3-48c3-bf02-79f2fcff7213), List(43673, 3
8448, 512, 36398, 1500, BpEwv+EcDv3z, 58f39535-03b7-4e05-a2d8-3f5b424c8938))
You can also do which reads a little better
scala> a.groupBy(_(5)).mapValues(_(0)).values.toList
res6: List[List[Any]] = List(List(302750, 759, 512, 759, 3796, BpEwv+EcDv3v, 069865df-30c3-48c3-bf02-79f2fcff7213), List(43673, 38448, 512, 36398, 1500, BpEwv+EcDv3z, 58f39535-03b7-4e05-a2d83f5b424c8938))
I have a collection of lists with each containing around 6 to 7 values. Like,
list1 = 2,4,7,4,9,5
list2 = 4,3,7.3,9,8,1.2
list3 = 2,2.4,7,9,8,5
list4 = 9,1.6,4,3,4,1
list5 = 2,5,7,9,1,4
list6 = 6,8,7,2,1,5
list7 = 4,2,5,2,1,3
Now I want to sort these with index1 as primary and index3 as secondary and index2 as tertiary and so on. That is, the output should be like:
2,2.4,7,9,8,5
2,4,7,4,9,5
2,5,7,9,1,4
4,2,5,2,1,3
6,8,7,2,1,5
9,1.6,4,3,4,1
I want the list order to be sorted for index1 first and if the values are same for index1 than sorting is done on index3 and if further same than on index2. Here the number of lists are less which can increase to 20 and the indexes can grow up to 20 as well.
The algorithm I want to know is the same as that of iTunes song sorting, in which songs with the same album are sorted first and then by artist and then by rank and then by name. That's the album's if album names are the same then sorting is done on the artist if same, then by rank and so on. The code can be in C/C++/tcl/shell.
sort -n -t ',' -k 1 -k 3 -k 2
Feed the lists as individual lines into it.
To do this in Tcl, assuming there's not huge amounts of data (a few MB wouldn't be “huge”) the easiest way would be:
# Read the values in from stdin, break into lists of lists
foreach line [split [read stdin] "\n"] {
lappend records [split $line ","]
}
# Sort twice, first by secondary key then by primary (lsort is _stable_)
set records [lsort -index 1 -real $records]
set records [lsort -index 0 -real $records]
# Write the values back out to stdout
foreach record $records {
puts [join $record ","]
}
If you're using anything more complex than simple numbers, consider using the csv package in Tcllib for parsing and formatting, as it will deal with many syntactic issues that crop up in Real Data. If you're dealing with a lot of data (where “lot” depends on how much memory you deploy with) then consider using a more stream-oriented method for handling the data (and there are a few other optimizations in the memory handling) and you might also want to use the -command option to lsort to supply a custom comparator so you can sort only once; the performance hit of a custom comparator is quite high, alas, but for many records the reduced number of comparisons will win out. Or shove the data into a database like SQLite or Postgres.
You can use STL's sort, and then all you have to do is to write a comparison function that does what you want (the example in the link should be good enough).
Since you asked for a Tcl solution:
set lol {
{2 4 7 4 9 5}
{4 3 7.3 9 8 1.2}
{2 2.4 7 9 8 5}
{9 1.6 4 3 4 1}
{2 5 7 9 1 4}
{6 8 7 2 1 5}
{4 2 5 2 1 3}
}
set ::EPS 10e-6
proc compareLists {ixo e1 e2} {
foreach ix $ixo {
set d [expr {[lindex $e1 $ix] - [lindex $e2 $ix]}]
if {abs($d) > $::EPS} {
return [expr {($d>0)-($d<0)}]
}
}
return 0
}
foreach li [lsort -command [list compareLists {0 2 1}] $lol] {
puts $li
}
Hope that helps.
Here is a C++ solution:
#include <iostream>
#include <vector>
#include <algorithm>
template <typename Array, typename CompareOrderIndex>
struct arrayCompare
{
private:
size_t
size ;
CompareOrderIndex
index ;
public:
arrayCompare( CompareOrderIndex idx ) : size( idx.size() ), index(idx) { }
bool helper( const Array &a1, const Array &a2, unsigned int num ) const
{
if( a1[ index[size-num] ] > a2[ index[size-num] ] )
{
return false ;
}
if( !(a1[ index[size-num] ] < a2[ index[size-num] ]) )
{
if( 1 != num )
{
return helper( a1, a2, num-1 ) ;
}
}
return true ;
}
bool operator()( const Array &a1, const Array &a2 ) const
{
return helper( a1, a2, size ) ;
}
} ;
int main()
{
std::vector< std::vector<float> > lists = { { 2, 4, 7, 4, 9, 5},
{ 4, 3, 7.3, 9, 8, 1.2 },
{ 2, 2.4, 7, 9, 8, 5 },
{ 4, 2, 5, 2, 1, 3 },
{ 9, 1.6, 4, 3, 4, 1 },
{ 2, 5, 7, 9, 1, 4 },
{ 6, 8, 7, 2, 1, 5 },
{ 4, 2, 5, 2, 1, 1 },
};
//
// Specify the column indexes to compare and the order to compare.
// In this case it will first compare column 1 then 3 and finally 2.
//
//std::vector<int> indexOrder = { 0, 2, 1, 3, 4 ,5 } ;
std::vector<int> indexOrder = { 0, 2, 1 } ;
arrayCompare< std::vector<float>, std::vector<int>> compV( indexOrder ) ;
std::sort( lists.begin(), lists.end(), arrayCompare< std::vector<float>, std::vector<int>>( indexOrder ) ) ;
for(auto p: lists)
{
for( unsigned int i = 0; i < p.size(); ++i )
{
unsigned int idx = ( i > (indexOrder.size() -1) ? i : indexOrder[i] ) ;
std::cout << p[idx] << ", " ;
}
std::cout << std::endl ;
}
}