I have 2 sets as below
jks - {<1 1> <1 2> <1 3> <2 1> <2 2> <2 3> <3 1> <3 2> <3 3>}
benchPerjk - [{1 3} {1 3} {1 3} {1 3} {1 3} {1 3} {1 2 3} {1 2 3} {1 2 3}]
I now want to find the next number in the benchPerjk for a certain jks
The code is as below
tuple jk {
int j;
int k;
}
{jk} jks = { <t.j, t.k> | t in PitBlocksType };
{int} BenchPerjk[v in jks] = { t.i | t in PitBlocksType : t.j == v.j && t.k == v.k };
Where the PitBlocksType come from the following data :
tuple blockType {
string id;
int i;
int j;
int k;
};
{blockType} PitBlocksType = ...; // Read from excel table which contains several rows, a short example below
/*
Example below
Block Id (i) (j) (k)
P1 1 1 1
P2 1 1 2
P3 1 1 3
P7 3 1 1
P8 3 1 2
P9 3 1 3
P10 1 2 1
P11 1 2 2
P12 1 2 3
P16 3 2 1
P17 3 2 2
P18 3 2 3
P19 1 3 1
P20 1 3 2
P21 1 3 3
P22 2 3 1
P23 2 3 2
P24 2 3 3
P25 3 3 1
P26 3 3 2
P27 3 3 3
*/
The reason why I am lookng for this is I want to use the BenchPerjk to find the next i. for using in the code below in place of the b.i+1
The b.i+1 works well if the i is continuous and all i is present for any set of j,k. Which means if Benchperjk would be
benchPerjk - [{1 2 3} {1 2 3} {1 2 3} {1 2 3} {1 2 3} {1 2 3} {1 2 3} {1 2 3} {1 2 3}]
But that is not the case in my data.
{blockType} OntopPit[b1 in PitBlocksType] =
{b | b in PitBlocksType: b1.i == b.i +1 &&
((b1.k == b.k-1 ) ||
(b1.k == b.k+1 ) ||
(b1.k == b.k ) ) &&
((b1.j == b.j-1 ) ||
(b1.j == b.j+1 ) ||
(b1.j == b.j ) ) };
Suggestions please.
I have tried the following code but it comes up with errors :
{blockType} OntopPit[b1 in PitBlocksType] =
{b | b in PitBlocksType: b1.i == next(BenchPerjk[< b.j , b.k>],b.i) &&
((b1.k == b.k-1 ) ||
(b1.k == b.k+1 ) ||
(b1.k == b.k ) ) &&
((b1.j == b.j-1 ) ||
(b1.j == b.j+1 ) ||
(b1.j == b.j ) ) };
but came up with 2 lines of error
"b.i" : next() element does not exist.
Invalid initialization expression for array item: OntopPit[<"P1",1,1,1>]
you could use next:
tuple jk {
int j;
int k;
}
{jk} jks = {<1 ,1> ,<1 ,2>, <1 ,3>, <2, 1> ,<2 ,2> ,<2, 3>, <3, 1> ,<3, 2>, <3, 3>};
{int} BenchPerjk[jks] = [{1 ,3}, {1, 3}, {1, 3} ,{1 ,3}, {1, 3}, {1, 3}, {1 ,2 ,3} ,{1 ,2, 3} ,{1 ,2, 3}];
// Now suppose you want to get the next after 1 for <j,k> = <2,1>
int res=next(BenchPerjk[<2,1>],1);
execute
{
writeln(res);
}
gives 3
Something more generic was later required:
tuple jk {
int j;
int k;
}
{jk} jks = {<1 ,1> ,<1 ,2>, <1 ,3>, <2, 1> ,<2 ,2> ,<2, 3>, <3, 1> ,<3, 2>, <3, 3>};
{int} BenchPerjk[jks] = [{1 ,3}, {1, 3}, {1, 3} ,{1 ,3}, {1, 3}, {1, 3}, {1 ,2 ,3} ,{1 ,2, 3} ,{1 ,2, 3}];
// Now suppose you want to get the next after 1 for <j,k> = <2,1>
int res=next(BenchPerjk[<2,1>],1);
execute
{
writeln(res);
}
// And now as a generic function
{int} benches=union (jk in jks) BenchPerjk[jk];
int nextone[jk in jks][i in benches]=(i in BenchPerjk[jk])?((i!=last(BenchPerjk[jk]))?next(BenchPerjk[jk],i):-2):-1;
int res2=nextone[<2,1>][1];
execute
{
writeln(res2);
}
gives
3
3
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»
I have come across a code where i get confused , An unordered_map is initialised like below
std::unordered_map<std::string, int> wordMap;
// Inserting elements through an initializer_list
wordMap.insert({ {"First", 1}, {"Second", 2}, {"Third", 3} } );
But what surprise me is the below code
int arr[] = { 1, 5, 2, 1, 3, 2, 1 };
unordered_map<int, int> hash;
for (int i = 0; i < n; i++)
hash[arr[i]]++;
Here i am not getting how key and value is inserted in the map
Here, In unordered_map, hash[arr[i]]++; works in this way:
It searches for a key (arr[i]). If it is found, the corresponding value is incremented by 1.
If it is not found, a new element will be created with key arr[i] and because value is of type int, default value of 0 is stored for it. Because of ++ operator, it will be incremented by one. So, at the end of the operation, the value will be 1.
To be very explicit for your example, it works like this:
i = 0 => arr[i] = 1 => Not present in map => New pair added => hash: [{1, 1}]
i = 1 => arr[i] = 5 => Not present in map => New pair added => hash: [{1, 1}, {5, 1}]
i = 2 => arr[i] = 2 => Not present in map => New pair added => hash: [{1, 1}, {5, 1}, {2, 1}]
i = 3 => arr[i] = 1 => Present in map => Existing pair updated => hash: [{1, 2}, {5, 1}, {2, 1}]
i = 4 => arr[i] = 3 => Not present in map => New pair added => hash: [{1, 2}, {5, 1}, {2, 1}, {3, 1}]
i = 5 => arr[i] = 2 => Present in map => Existing pair updated => hash: [{1, 2}, {5, 1}, {2, 2}, {3, 1}]
i = 6 => arr[i] = 1 => Present in map => Existing pair updated => hash: [{1, 3}, {5, 1}, {2, 2}, {3, 1}]
The order mentioned here might be different from actual one. The above explanation is just to explain things.
The key of the unordered map must be unique so all 1:s will be combined. But when they do combine the loop will add 1 to the value side:
hash[arr[i]]++ will be equal to this example: hash[1] += 1;
Since there are three 1 values, hash[1] will end up with a value of 3. You will find two records of the value 2 and this will make hash[2] = 2.
#include <iostream>
#include <unordered_map>
int main()
{
int arr[] = { 1, 5, 2, 1, 3, 2, 1 };
std::unordered_map<int, int> hash;
for (int i = 0; i < 7; i++) {
hash[arr[i]] += 1;
}
for (auto i : hash) {
printf("%i:%i\n", i.first, i.second);
}
}
# Output:
# 3:1
# 2:2
# 5:1
# 1:3
operator[] checks if the element exists. If it doesn't then it creates one using default constructor and returns a reference (or const reference to it). ie :
hash[arr[0]]++
it creates hash[1]first
which is
hash[1]++ => hash[1]=hash[1]+1 which is 0+1 ( since hash[1] at the begining was 0 by default.. )
when it get to the second 1 it become hash[1]=hash[1]+1 = 2 ...
..ect same for other values
basically it s creating & counting the number of the duplicates in the array
at the end it gives you
hash[1]=3
hash[2]=2
hash[3]=1
hash[5]=1
I have the following data:
player_id level talent_id
1 1 a
1 2 b
1 3 c
2 1 d
2 2 e
And want to group by player_id and have rows as structs, with level values as struct field names:
player_id data
1 {_1 = a, _2 = b, _3 = c}
2 {_1 = d, _2 = e, _3 = null}
the level column is always from the set of {1, 2, 3} but some levels might be missing (null)
What I've got so far is aggregation by player_id and with attached array of results:
talents as (
select
p.player_id,
array_agg(struct(p.level, p.talent_id)) as talents
from source.player_talent p
group by player_id
),
player_id data
1 [{1, a}, {2, b}, {3, c}]
2 {{1, d}, {2, e}]
now I need to map this array to a struct with fixed property names _1, _2, _3
This returns the expected results:
WITH Players AS (
SELECT 1 AS player_id, 1 AS level, 'a' AS talent_id UNION ALL
SELECT 1, 2, 'b' UNION ALL
SELECT 1, 3, 'c' UNION ALL
SELECT 2, 1, 'd' UNION ALL
SELECT 2, 2, 'e'
)
SELECT
player_id,
STRUCT(
MAX(IF(level = 1, talent_id, NULL)) AS _1,
MAX(IF(level = 2, talent_id, NULL)) AS _2,
MAX(IF(level = 3, talent_id, NULL)) AS _3) AS data
FROM Players
GROUP BY player_id
The technique here is known as pivoting (converting rows to columns).
I'm looking for a function that returns a map[string]interface{} where interface{} can be a slice, a a map[string]interface{} or a value.
My use case is to parse WKT geometry like the following and retrieves point values; Example for a donut polygon:
POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0),(3 3, 3 7, 7 7, 7 3, 3 3))
The regex (I voluntary set \d that matches only integers for readability purpose):
(POLYGON \(
(?P<polygons>\(
(?P<points>(?P<point>(\d \d), ){3,})
(?P<last_point>\d \d )\),)*
(?P<last_polygon>\(
(?P<points>(?P<point>(\d \d), ){3,})
(?P<last_point>\d \d)\))\)
)
I have a function (copied from SO) that retrieves some informations but it's not that good for nested groups and list of groups:
func getRegexMatchParams(reg *regexp.Regexp, url string) (paramsMap map[string]string) {
match := reg.FindStringSubmatch(url)
paramsMap = make(map[string]string)
for i, name := range reg.SubexpNames() {
if i > 0 && i <= len(match) {
paramsMap[name] = match[i]
}
}
return match
}
It seems that the group point gets only 1 point.
example on playground
[EDIT] The result I want is something like this:
map[string]interface{}{
"polygons": map[string]interface{} {
"points": []interface{}{
{map[string]string{"point": "0 0"}},
{map[string]string{"point": "0 10"}},
{map[string]string{"point": "10 10"}},
{map[string]string{"point": "10 0"}},
},
"last_point": "0 0",
},
"last_polygon": map[string]interface{} {
"points": []interface{}{
{map[string]string{"point": "3 3"}},
{map[string]string{"point": "3 7"}},
{map[string]string{"point": "7 7"}},
{map[string]string{"point": "7 3"}},
},
"last_point": "3 3",
}
}
So I can use it further for different purposes like querying databases and validate that last_point = points[0] for each polygon.
Try to add some whitespace to the regex.
Also note that this engine won't retain all capture group values that are
within a quantified outer grouping like (a|b|c)+ where this group will only contain the last a or b or c it finds.
And, your regex can be reduced to this
(POLYGON\s*\((?P<polygons>\(\s*(?P<points>(?P<point>\s*(\d+\s+\d+)\s*,){3,})\s*(?P<last_point>\d+\s+\d+)\s*\)(?:\s*,\s*|\s*\)))+)
https://play.golang.org/p/rLaaEa_7GX
The original:
(POLYGON\s*\((?P<polygons>\(\s*(?P<points>(?P<point>\s*(\d+\s+\d+)\s*,){3,})\s*(?P<last_point>\d+\s+\d+)\s*\),)*(?P<last_polygon>\(\s*(?P<points>(?P<point>\s*(\d+\s+\d+)\s*,){3,})\s*(?P<last_point>\d+\s+\d+)\s*\))\s*\))
https://play.golang.org/p/rZgJYPDMzl
See below for what the groups contain.
( # (1 start)
POLYGON \s* \(
(?P<polygons> # (2 start)
\( \s*
(?P<points> # (3 start)
(?P<point> # (4 start)
\s*
( \d+ \s+ \d+ ) # (5)
\s*
,
){3,} # (4 end)
) # (3 end)
\s*
(?P<last_point> \d+ \s+ \d+ ) # (6)
\s* \),
)* # (2 end)
(?P<last_polygon> # (7 start)
\( \s*
(?P<points> # (8 start)
(?P<point> # (9 start)
\s*
( \d+ \s+ \d+ ) # (10)
\s*
,
){3,} # (9 end)
) # (8 end)
\s*
(?P<last_point> \d+ \s+ \d+ ) # (11)
\s* \)
) # (7 end)
\s* \)
) # (1 end)
Input
POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0),(3 3, 3 7, 7 7, 7 3, 3 3))
Output
** Grp 0 - ( pos 0 , len 65 )
POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0),(3 3, 3 7, 7 7, 7 3, 3 3))
** Grp 1 - ( pos 0 , len 65 )
POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0),(3 3, 3 7, 7 7, 7 3, 3 3))
** Grp 2 [polygons] - ( pos 9 , len 30 )
(0 0, 0 10, 10 10, 10 0, 0 0),
** Grp 3 [points] - ( pos 10 , len 23 )
0 0, 0 10, 10 10, 10 0,
** Grp 4 [point] - ( pos 27 , len 6 )
10 0,
** Grp 5 - ( pos 28 , len 4 )
10 0
** Grp 6 [last_point] - ( pos 34 , len 3 )
0 0
** Grp 7 [last_polygon] - ( pos 39 , len 25 )
(3 3, 3 7, 7 7, 7 3, 3 3)
** Grp 8 [points] - ( pos 40 , len 19 )
3 3, 3 7, 7 7, 7 3,
** Grp 9 [point] - ( pos 54 , len 5 )
7 3,
** Grp 10 - ( pos 55 , len 3 )
7 3
** Grp 11 [last_point] - ( pos 60 , len 3 )
3 3
Possible Solution
It's not impossible. It just takes a few extra steps.
(As an aside, isn't there a library for WKT that can parse this for you ?)
Now, I don't know your language capabilities, so this is just a general approach.
1. Validate the form you're parsing.
This will validate and return all polygon sets as a single string in All_Polygons group.
Target POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0),(3 3, 3 7, 7 7, 7 3, 3 3))
POLYGON\s*\((?P<All_Polygons>(?:\(\s*\d+\s+\d+(?:\s*,\s*\d+\s+\d+){2,}\s*\))(?:\s*,\(\s*\d+\s+\d+(?:\s*,\s*\d+\s+\d+){2,}\s*\))*)\s*\)
** Grp 1 [All_Polygons] - ( pos 9 , len 55 )
(0 0, 0 10, 10 10, 10 0, 0 0),(3 3, 3 7, 7 7, 7 3, 3 3)
2. If 1 was successful, set up a loop match using the output of All_Polygons string.
Target (0 0, 0 10, 10 10, 10 0, 0 0),(3 3, 3 7, 7 7, 7 3, 3 3)
(?:\(\s*(?P<Single_Poly_All_Pts>\d+\s+\d+(?:\s*,\s*\d+\s+\d+){2,})\s*\))
This step is equivalent of a find all type of match. It should match successive values of all the points of a single polygon, returned in Single_Poly_All_Pts group string.
This will give you these 2 separate matches, which can be put into a temp array having 2 value strings:
** Grp 1 [Single_Poly_All_Pts] - ( pos 1 , len 27 )
0 0, 0 10, 10 10, 10 0, 0 0
** Grp 1 [Single_Poly_All_Pts] - ( pos 31 , len 23 )
3 3, 3 7, 7 7, 7 3, 3 3
3. If 2 was successful, set up a loop match using the temp array output of step 2.
This will give you the individual points of each polygon.
(?P<Single_Point>\d+\s+\d+)
Again this is a loop match (or a find all type of match). For each array element
(Polygon), this will produce the individual points.
Target[element 1] 0 0, 0 10, 10 10, 10 0, 0 0
** Grp 1 [Single_Point] - ( pos 0 , len 3 )
0 0
** Grp 1 [Single_Point] - ( pos 5 , len 4 )
0 10
** Grp 1 [Single_Point] - ( pos 11 , len 5 )
10 10
** Grp 1 [Single_Point] - ( pos 18 , len 4 )
10 0
** Grp 1 [Single_Point] - ( pos 24 , len 3 )
0 0
And,
Target[element 2] 3 3, 3 7, 7 7, 7 3, 3 3
** Grp 1 [Single_Point] - ( pos 0 , len 3 )
3 3
** Grp 1 [Single_Point] - ( pos 5 , len 3 )
3 7
** Grp 1 [Single_Point] - ( pos 10 , len 3 )
7 7
** Grp 1 [Single_Point] - ( pos 15 , len 3 )
7 3
** Grp 1 [Single_Point] - ( pos 20 , len 3 )
3 3
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 ;
}
}