How to sort a Vec by indices? - sorting

I want to sort (reorder) a Vec in-place by a predefined ordering in Rust.
For example:
let i = vec![0, 3, 2, 1];
let mut v = vec!["a", "b", "c", "d"];
v.sort_by_indices(&i);
assert_eq!(v, &["a", "d", "c", "b"]);
I would like to do this in-place. In my use case, v takes up a lot of memory.
This question is a follow-up to How to get the indices that would sort a Vec?

An in-place implementation is tricky but possible in O(n) time. It works by chasing indices and swapping elements until it gets back to where it started. Unfortunately, this does require scratch space to keep track of what elements are already sorted. Here's an implementation that reuses the index array if its allowed to consume it:
fn sort_by_indices<T>(data: &mut [T], mut indices: Vec<usize>) {
for idx in 0..data.len() {
if indices[idx] != idx {
let mut current_idx = idx;
loop {
let target_idx = indices[current_idx];
indices[current_idx] = current_idx;
if indices[target_idx] == target_idx {
break;
}
data.swap(current_idx, target_idx);
current_idx = target_idx;
}
}
}
}
See it working on the playground (with improvements by #Jmb).
Otherwise you would need a separate allocation for the scratch space (perhaps a BitVec). Feel free to comment or edit if this method is possible without keeping track of the sorted elements.

In the same way it enough to implement yourself
let i = vec![0, 3, 2, 1];
let mut v = vec!["a", "b", "c", "d"];
v = i.into_iter().map(|x| v[x]).collect::<Vec<&str>>();
assert_eq!(v, &["a", "d", "c", "b"]);

You can create a HashMap or BTreeMap lookup table and use it as key searcher:
use std::collections::HashMap;
fn main() {
let i = vec![0, 3, 2, 1];
let mut v = vec!["a", "b", "c", "d"];
let keys: HashMap<_, _> = v.iter().cloned().zip(i.iter()).collect();
v.sort_by_cached_key(|e| keys[e]);
assert_eq!(v, &["a", "d", "c", "b"]);
}
Playground

Related

Java/Kotlin - convert Set to Map<Long, Set<Long>>

I have Set of Long values
Set<Long> ids = {1,2,3,4}
What I'd like to achieve is
Set<Map<Long, Set<Long>>
and from this Set of ids I need to have Set with 4 elements like:
Set: {
Map -> key: 1, values: 2,3,4
Map -> key: 2, values: 1,3,4
Map -> key: 3, values: 1,2,4
Map -> key: 4, values: 1,2,3
}
How can i get it by stream or maybe kotlin's groupBy ?
Was anyone going to have a map like this? (Solution without a for or while loop)
You can use use map method to transform every element to Map then collect it to set
var set = setOf(1, 2, 3, 4)
var map = set.map { v -> mapOf(v to set.filter { it != v }.toSet()) }
.toSet()
However I don't believe it's much better than simple foreach loop due to performance or readability
Opinions on kotlin groupBy
Notice that groupBy can just split the original set into severial sets without intersection. So it's impossible to construct the mentioned map directly with groupBy function.
The solution below take advantage of groupBy when getting result, but result2 is much more clear to read and meets intuition:
fun main() {
val set = setOf(1, 2, 3, 4)
val result = set
.groupBy { it }
.mapValues { (_, values) -> set.filter { it !in values } }
println(result) // {1=[2, 3, 4], 2=[1, 3, 4], 3=[1, 2, 4], 4=[1, 2, 3]}
val result2 = HashMap<Int, List<Int>>().apply {
set.forEach { this[it] = (set - it).toList() }
}
println(result2) // {1=[2, 3, 4], 2=[1, 3, 4], 3=[1, 2, 4], 4=[1, 2, 3]}
}
That would be a possible solution with a for loop:
val ids: Set<Long> = setOf(1, 2, 3, 4)
var result: MutableSet<Map<Long, Set<Long>>> = mutableSetOf()
for (id in ids) {
result.add(mapOf(id to ids.filter { it != id }.toSet()))
}
println(result)

Most idiomatic way to create cycled and infinite range of integers in Java 8

In ruby you can do something like this
a = ["a", "b", "c"]
a.cycle {|x| puts x } # print, a, b, c, a, b, c,.. forever.
a.cycle(2) {|x| puts x } # print, a, b, c, a, b, c.
and this is just beautiful.
The closest analog in Java 8 would be like this:
Stream<Integer> iterator = Stream.iterate(new int[] {0, 0}, p -> new int[]{p[0] + 1, (p[0] + 1) % 2}).map(el -> el[1]);
Iterator<Integer> iter = iterator.iterator();
System.out.println(iter.next());//0
System.out.println(iter.next());//1
System.out.println(iter.next());//0
System.out.println(iter.next());//1
Is there a better way and more idiomatic to do it in Java?
Update
Just want to outline here that the closest solution to my problem was
IntStream.generate(() -> max).flatMap(i -> IntStream.range(0, i))
Thanks to #Hogler
You may use
String[] array = { "a", "b", "c" };
Stream.generate(() -> array).flatMap(Arrays::stream).forEach(System.out::println);
to print a b c forever and
String[] array = { "a", "b", "c" };
Stream.generate(() -> array).limit(2).flatMap(Arrays::stream).forEach(System.out::println);
to print a b c two times.
This doesn’t even require an existing array:
Stream.generate(() -> null)
.flatMap(x -> Stream.of("a", "b", "c"))
.forEach(System.out::println);
resp.
Stream.generate(() -> null).limit(2)
.flatMap(x -> Stream.of("a", "b", "c"))
.forEach(System.out::println);
you could also use
IntStream.range(0, 2).boxed()
.flatMap(x -> Stream.of("a", "b", "c"))
.forEach(System.out::println);
Well if you define the array variable outside the stream, you can use indexes instead. And you will have something like:
String[] array = { "a", "b", "c" };
Stream.iterate(0, i -> (i + 1) % array.length)
.map(i -> array[i])
.forEach(System.out::println); // prints a, b, c forever
Stream.iterate(0, i -> (i + 1) % array.length)
.map(i -> array[i])
.limit(2 * array.length)
.forEach(System.out::println); // prints a, b, c 2 times
Also can use nCopies you don't need to use array.length:
Collections.nCopies(2, array).stream()
.flatMap(Arrays::stream)
.forEach(System.out::println); // prints a, b, c 2 times
It is obviously longer than the ruby version, but that's how usually java is (more verbose)

Tree Level-Order Traversal of Elements in a Vector

I am looking for an algorithm to take a list of x values and loop through them starting in the middle then the middle of the left then the middle of the right, then the middle of the middle of the left...like a tree.
I don't think recursion will work because it will traverse down one side completely before getting to the other side. I need to parse through evenly.
Pretend this is a list of 50 numbers:
.................................................. (50)
Need to find the 25th element first
........................1......................... (lvl1)
Then the 12th, then 38th
...........2.........................3............ (lvl2)
Then the 6,18 31,44
.....4...........5.............6...........7...... (lvl3)
Then the 3,9,15,21 28,34,41,48
..8.....9.....a......b.....c.......d.....e.....f.. (lvl4)
etc... until all the values have been traversed. So by the time lvl4 is hit, i've seen 1,2,3,4,5,6,7,8,9,a,b,c,d,e,f in that order.
All my attempts have flopped to do this iteratively.
Efficiency is not critical as it won't be run often.
Hopefully my question is clear. Thank-you
You can solve this via a queue data structure and some math.
Start by pushing in the tuple (0, 25, 49). This indicates that this is a node at position 25, splitting the range 0-49. So the queue should look like this:
[(0, 25, 49)]
Now at each point, remove the front of the queue, print the element at the index, and push in the descendants. So, for example, when you pop (0, 25, 49), how to track the descendants? The left descendant is the middle of the range 0-24, so you would push in (0, 12, 24). The right descendant is the middle of the range 26-49, so you would push in (26, 38, 49). So the queue should look like this:
[(0, 13, 23), (26, 38, 49)].
Et cetera.
(The solution that follows is written in Swift, but I hope you can follow it and translate to your favourite language of choice, in case you wish to make use of it)
We can quite easily come up with a solution that works in the special case where your number of array values describe a full(/proper) binary tree, i.e., if numElements = 2^(lvl-1)+1, where lvl is the level of your tree. See function printFullBinaryTree(...) below.
Now, we can also somewhat with ease expand any array into one that describes a full binary tree, see expandToFullBinary. '
By combining these two methods, we have a general method for input arrays of any size.
Expand any array into one that describes a full binary tree:
/* given 'arr', returns array expanded to full binary tree (if necessary) */
func expandToFullBinary(arr: [String], expandByCharacter: String = "*") -> [String] {
let binLength = Int(pow(2.0,Double(Int(log2(Double(arr.count)))+1)))-1
if arr.count == binLength {
return arr
}
else {
let diffLength = binLength - arr.count
var arrExpanded = [String](count: binLength, repeatedValue: expandByCharacter)
var j = 0
for i in 0 ..< arr.count {
if i < (arr.count - diffLength) {
arrExpanded[i] = arr[i]
}
else {
arrExpanded[i+j] = arr[i]
j = j+1
}
}
return arrExpanded
}
}
Print array (that describes a full binary tree) as a binary tree according to your question specifications:
/* assumes 'arr' describes a full binary tree */
func printFullBinaryTree(arr: [String]) {
var posVectorA : [Int] = [arr.count/2]
var posVectorB : [Int]
var splitSize : Int = arr.count/2
var elemCount = 0
if arr.count < 2 {
print("\(arr.first ?? "")")
}
else {
while elemCount < arr.count {
posVectorB = []
splitSize = splitSize/2
for i in posVectorA {
if elemCount == arr.count {
print("noo")
break
}
print(arr[i], terminator: " ")
elemCount = elemCount + 1
posVectorB.append(i-splitSize-1)
posVectorB.append(i+splitSize+1)
}
print("")
posVectorA = posVectorB
}
}
}
Example for a vector describing a full binary tree as well as one describing a non-full binary tree:
/* Example */
var arrFullBinary : [String] = ["8", "4", "9", "2", "a", "5", "b", "1", "c", "6", "d", "3", "e", "7", "f"]
var arrNonFullBinary : [String] = ["g", "8", "h", "4", "i", "9", "j", "2", "a", "5", "b", "1", "c", "6", "d", "3", "e", "7", "f"]
printFullBinaryTree(expandToFullBinary(arrFullBinary, expandByCharacter: ""))
/* 1
2 3
4 5 6 7
8 9 a b c d e f */
printFullBinaryTree(expandToFullBinary(arrNonFullBinary, expandByCharacter: ""))
/* 1
2 3
4 5 6 7
8 9 a b c d e f
g h i j */

Lua - Sort table and randomize ties

I have a table with two values, one is a name (string and unique) and the other is a number value (in this case hearts). What I want is this: sort the table by hearts but scramble randomly the items when there is a tie (e.g. hearts is equal). By a standard sorting function, in case of ties the order is always the same and I need it to be different every time the sorting function works.
This is anexample:
tbl = {{name = "a", hearts = 5}, {name = "b", hearts = 2}, {name = "c", hearts = 6}, {name = "d", hearts = 2}, {name = "e", hearts = 2}, {name = "f", hearts = 7}}
sort1 = function (a, b) return a.hearts > b.hearts end
sort2 = function (a, b)
if a.hearts ~= b.hearts then return a.hearts > b.hearts
else return a.name > b.name end
end
table.sort(tbl, sort2)
local s = ""
for i = 1, #tbl do
s = s .. tbl[i].name .. "(" .. tbl[i].hearts .. ") "
end
print(s)
Now, with the function sort2 I think I quite got the problem. The problem is, what happens when a.hearts == b.hearts? In my code it just orders the ties by their name, not what I want. I have two ideas:
First scramble randomly all the items in the table, then apply sort1.
Add a value to every element of the table, called rnd, that is a random number. Then in sort2, when a.hearts == b.hearts order the items by a.rnd > b.rnd.
In sort2, when a.hearts == b.hearts generate randomly true or false and return it. It doesn't work, and I understand that this happens because the random true/false makes the order function crash since there could be inconsistencies.
I don't like 1 (because I would like to do everything inside the sorting function) and 2 (since it requires to add a value), I would like to do something like 3 but working. The question is: is there a way do to this in a simple manner, and what is an optimal way of doing this? (maybe, method 1 or 2 are optimal and I don't get it).
Bonus question. Moreover, I need to fix an item and sort the others. For example, suppose we want "c" to be first. Is it good to make a separate table with only the items to sort, sort the table and then add the fixed items?
-- example table
local tbl = {
{ name = "a", hearts = 5 },
{ name = "b", hearts = 2 },
{ name = "c", hearts = 6 },
{ name = "d", hearts = 2 },
{ name = "e", hearts = 2 },
{ name = "f", hearts = 7 },
}
-- avoid same results on subsequent requests
math.randomseed( os.time() )
---
-- Randomly sort a table
--
-- #param tbl Table to be sorted
-- #param corrections Table with your corrections
--
function rnd_sort( tbl, corrections )
local rnd = corrections or {}
table.sort( tbl,
function ( a, b)
rnd[a.name] = rnd[a.name] or math.random()
rnd[b.name] = rnd[b.name] or math.random()
return a.hearts + rnd[a.name] > b.hearts + rnd[b.name]
end )
end
---
-- Show the values of our table for debug purposes
--
function show( tbl )
local s = ""
for i = 1, #tbl do
s = s .. tbl[i].name .. "(" .. tbl[i].hearts .. ") "
end
print(s)
end
for i = 1, 10 do
rnd_sort(tbl)
show(tbl)
end
rnd_sort( tbl, {c=1000000} ) -- now "c" will be the first
show(tbl)
Here's a quick function for shuffling (scrambling) numerically indexed tables:
function shuffle(tbl) -- suffles numeric indices
local len, random = #tbl, math.random ;
for i = len, 2, -1 do
local j = random( 1, i );
tbl[i], tbl[j] = tbl[j], tbl[i];
end
return tbl;
end
If you are free to introduce a new dependency, you can use lazylualinq to do the job for you (or check out how it sorts sequences, if you do not need the rest):
local from = require("linq")
math.randomseed(os.time())
tbl = {{name = "a", hearts = 5}, {name = "b", hearts = 2}, {name = "c", hearts = 6}, {name = "d", hearts = 2}, {name = "e", hearts = 2}, {name = "f", hearts = 7}}
from(tbl)
:orderBy("x => x.hearts")
:thenBy("x => math.random(-1, 1)")
:foreach(function(_, x) print(x.name, x.hearts) end)

What is the best way to convert an array to a hash?

I have an array: a = ["a", "b", "c"] and I want convert to a hash h = {1=>"a", 2=>"b", 3=>"c"}
where the key is the position of the array. Any ideas?
One way in Ruby would be:
h = Hash[a.map.with_index { |s, i| [ i + 1, s ] }]
If you a.map without a block, you get an Enumerator object, then you can get the indexes by iterating over that Enumerator with with_index. Then it is just a simple matter of adjusting the starting index and arranging things in the right order for Hash[].
You could also do it this way (which is pretty much a transliteration of House's Java answer):
h = { }
a.each_with_index { |s, i| h[i + 1] = s }
Which way you do it is mostly a matter of taste.
a = ["a", "b", "c"]
Hash[(1..a.length).zip(a)]
1..a.length gives you [1,2,3] (after an implicit conversion)
zip(a) gives you [1,"a",2,"b",3,"c"]
Just loop over the array, in Java it would be the following.
Map<Integer, String> map = new HashMap<Integer, String>();
for (int i = 0; i < array.length; i++) {
map.put(Integer.valueOf(i), array[i]);
}
Try it in Python:
>>> dict((k, v) for k, v in enumerate(["a", "b", "c"]))
{0: 'a', 1: 'b', 2: 'c'}
a = ["a", "b", "c"]
Hash[a.map.with_index(1){|i,ind| [ind,i] }]
# >> {1=>"a", 2=>"b", 3=>"c"}

Resources