Related
I'd like to sort a Vector of structs, using some sort of closure-like format. Here's what I was thinking:
struct PointTracker {
positive: u32,
negative: u32,
}
// ....
fn main() {
let item: Vec<PointTracker> // ....
// e.g: [{positive: 3, negative: 4}, {positive: 5, negative: 0}, {positive: 2, negative: 10}]
let sorted_item = item
.iter()
.sort_with(|x: PointTracker| x.positive - x.negative)
.collect::<PointTracker>();
// sorted from greatest to least:
// [{positive: 5, negative: 0}, {positive: 3, negative: 4}, {positive:2, negative: 10}]
}
What I was looking for is some sort of function, like above, that sorts items based on the value returned in the closure. This takes the positive value, subtracts the negative from it, and returns the result. The first unsorted items' sums would be: [-1, 5, -8] and the sorted's sums would be (as expected): [5, -1, -8]
Is there some sort of crate for this function, or should I write my own if it doesn't exist?
The function you are searching for is sort_by_key:
#[derive(Debug)]
struct PointTracker {
positive: u32,
negative: u32,
}
fn main() {
let mut item = vec![
PointTracker {
positive: 3,
negative: 4,
},
PointTracker {
positive: 5,
negative: 0,
},
PointTracker {
positive: 2,
negative: 10,
},
];
item.sort_by_key(|x| x.positive as i32 - x.negative as i32);
println!("{:#?}", item);
}
Output:
[
PointTracker {
positive: 2,
negative: 10,
},
PointTracker {
positive: 3,
negative: 4,
},
PointTracker {
positive: 5,
negative: 0,
},
]
I am writing microservice in Dart.
Service run workers by passing command args to workers like: "app.exe -a=1,2,3,4".
So if currentlyActiveWorkers is 4. Then jobs can be splited to sevaral workers like:
first: "app.exe -a=1,2,3,4"
second: "app.exe -a=5,6,7,8"
third: "app.exe -a=9,10,11,12"
fourth: "app.exe -a=13,14,15,16".
I wrote next prototype:
void main() {
int maxWorkers = 16;
int currentlyActiveWorkers = 2;
genJobs() {
int step = 1;
int sliceSize = (maxWorkers/currentlyActiveWorkers).round();
var list = [for(var i=step; i<=maxWorkers; i+=1) i];
for(int i in Iterable<int>.generate(currentlyActiveWorkers))
{
print(list.sublist(i * sliceSize, sliceSize * step));
step++;
}
}
genJobs();
}
It work fine if currentlyActiveWorkers is multiple of 2. It's generate suitable jobs numbers:
[1, 2, 3, 4, 5, 6, 7, 8]
[9, 10, 11, 12, 13, 14, 15, 16]
But there is bug if user specify for example 3. Last number 16 is loosing.
Output:
[1, 2, 3, 4, 5]
[6, 7, 8, 9, 10]
[11, 12, 13, 14, 15]
It does not matter for me the number element in every group +- 1 is ok for me.
Your rounding logic is ambiguous. Besides, you should handle the last chunk of data in different way:
void main() {
print(genJobs());
}
Map<int, List<int>> genJobs() {
final activeWorkers = 3;
final maxJobs = 16;
final jobs = List<int>.generate(maxJobs, (i) => i + 1);
final workerCapacity = (jobs.length / activeWorkers).floor();
var chunks = <int, List<int>>{};
for (var workerNumber = 0; workerNumber < activeWorkers; workerNumber++) {
final startIndex = workerNumber * workerCapacity;
final endIndex = startIndex + workerCapacity;
final chunk = jobs.sublist(
startIndex,
endIndex > jobs.length || workerNumber == activeWorkers - 1
? jobs.length
: endIndex,
);
chunks.addAll({workerNumber: chunk});
}
return chunks;
}
Your problem is that you are picking a fixed size for the slices first, even when the number of elements isn't a multiple of the slice count. You're lucky that it rounded down instead of up, otherwise you'd have gotten an index-out-of-range error (try your code with 17 elements and three groups).
First you should figure our what result you want. Then you can try coding that.
For something like 22 elements and four groups, you probably want two groups of 6 elements and two groups of 5 elements, not three groups of 6 and one of 4 (since you say +/-1 is OK, not +/- 2).
I would do something like:
/// Emits the integers from 0 to [elementCount] - 1 in [groupCount] grups.
///
/// The [elementCount] must be greater than zero.
/// The [groupCount] must be in the range 1..[elementCount],
/// meaning that each group will have at least one element, and
/// each element is in at least one group.
Iterable<List<int>> evenlySpreadGroups(int elementCount, int groupCount) sync* {
if (elementCount < 1) {
throw RangeError.range(elementCount, 1, null, "elementCount");
}
RangeError.checkValueInInterval(groupCount, 1, elementCount, "groupCount");
var list = <int>[];
var groupIndex = 1;
for (var i = 0; i < elementCount; i++) {
while (i * groupCount >= groupIndex * elementCount) {
yield list;
list = [];
groupIndex += 1;
}
list.add(i);
}
yield list;
}
(It's written to also work if you allow more groups than elements, any groupCount >= 1, you'll just get empty lists in the output which is just rarely useful).
The more solutions the better:
import 'package:lists/lists.dart';
void main() {
final maxPartSize1 = 5;
final data1 = genData(1, 16);
print('data: $data1');
final parts1 = split(data1, maxPartSize1);
print('parts by $maxPartSize1: $parts1');
print('=====');
final maxPartSize2 = 3;
final data2 = genData(2, 8);
print('data: $data2');
final parts2 = split(data2, maxPartSize2);
print('parts by $maxPartSize2: $parts2');
}
List<int> genData(int start, int length) {
return List<int>.generate(length, (i) => i + start);
}
Iterable<List<int>> split(List<int> data, int step) sync* {
final length = data.length;
for (final i in StepList(0, length - 1, step)) {
var i2 = i + step;
if (i2 > length) {
i2 = length;
}
yield data.sublist(i, i2);
}
}
Output:
data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
parts by 5: ([1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15], [16])
=====
data: [2, 3, 4, 5, 6, 7, 8, 9]
parts by 3: ([2, 3, 4], [5, 6, 7], [8, 9])
Another way:
void main() {
final maxWorkers1 = 8;
final datLen1 = 16;
final data1 = [1, 2, 5, 6, 9, 10, 11, 12, 13, 14, 15, 16];
print('data: $data1');
final parts1 = split(data1, maxWorkers1);
print('$maxWorkers1 workers: $parts1');
print('=====');
final maxWorkers2 = 4;
final datLen2 = 11;
final data2 = genData(3, datLen2);
print('data: $data2');
final parts2 = split(data2, maxWorkers2);
print('$maxWorkers2 workers: $parts2');
print('=====');
final maxWorkers3 = 8;
final data3 = [7, 8, 3, 4];
print('data: $data3');
final parts3 = split(data3, maxWorkers3);
print('$maxWorkers3 workers: $parts3');
}
List<int> genData(int start, int length) {
return List<int>.generate(length, (i) => i + start);
}
Iterable<List<int>> split(List<int> data, int divider) sync* {
if (divider <= 0) {
throw RangeError.value(divider, 'divider', 'Must be greater than 0');
}
if (data.isEmpty) {
// Nothing to do
return;
}
final length = data.length;
divider = divider > length ? length : divider;
var partSize = length ~/ divider;
if (length != partSize * divider) {
partSize++;
}
for (var i = 0; i < divider; i++) {
final start = i * partSize;
if (start >= length) {
break;
}
var end = start + partSize;
if (end > length) {
end = length;
}
yield data.sublist(start, end);
}
}
Output:
data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
3 workers: ([1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12], [13, 14, 15, 16])
=====
data: [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
4 workers: ([3, 4, 5], [6, 7, 8], [9, 10, 11], [12, 13])
=====
data: [7, 8, 3, 4]
8 workers: ([7], [8], [3], [4])
Following up with this, I have a bunch of coordinates and I draw them on a bitmap image as a coordinate system. Now, I would like to get rid of all the noise, and filter coordinates to give a "clearer" or "cleaner" path and "less" or "better" data to work on. To explain more, I will need to expose my awesome painting skills as follows:
Current:
Desired:
Notice:
I will need to delete coordinates
I might need to add coordinates
I might need to ignore shortest neighbor in some cases
The only thing I can think of, is to use a shortest path algorithm such as A* and Dijkstra. And populate data in some sort of data structure to contain neighbors and costs for every node and then to execute the algorithm. I don't want to start something that might be wrong or waste. I would love to see a pseudo code if possible on how could I solve such a problem?
P.S I am currently on Wpf C# but I am open to use C# or C++ for any task. Thanks
You are looking for an operation called thinning or skeletonization, possibly followed by some post-processing to remove small components. There are different algorithms for this that offer different properties. For example Guo and Hall's and Zhang and Suen's.
What you're after is a path finding application. There are several ways to approach this, but one of the simpler ways is to:
Pick a starting point, add to list
While True:
For each border_pt bordering last point on list:
Count number of points bordering border_pt
If count > best_count:
Mark border_pt as best
if border_pt is empty:
break
Add border_pt to list
Here's some C# code that does just that, it generates a simple list based on your cloud:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
class ExampleProgram : Form
{
const int GridWidth = 24;
const int GridHeight = 15;
List<Point> m_points = new List<Point>();
List<Point> m_trail = new List<Point>();
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new ExampleProgram());
}
ExampleProgram()
{
// Simple little tool to add a bunch of points
AddPoints(
0, 4, 1, 3, 1, 4, 1, 5, 2, 4, 2, 5, 2, 6, 3, 4, 3, 5, 4, 5, 4, 6, 5, 5, 6, 5,
6, 4, 5, 4, 7, 4, 7, 3, 8, 3, 8, 4, 8, 5, 8, 6, 9, 6, 9, 5, 9, 4, 9, 3, 10, 2,
10, 3, 10, 4, 10, 5, 10, 6, 11, 5, 11, 4, 11, 3, 11, 2, 12, 4, 12, 5, 13, 5,
13, 6, 13, 8, 14, 8, 14, 7, 14, 6, 15, 7, 15, 8, 15, 9, 14, 9, 14, 10, 13, 10,
12, 10, 11, 10, 13, 11, 14, 11, 15, 11, 15, 12, 16, 12, 17, 12, 18, 12, 19,
12, 18, 11, 17, 11, 17, 10, 18, 10, 19, 10, 19, 9, 19, 8, 20, 8, 21, 8, 18,
7, 19, 7, 20, 7, 21, 7, 21, 6, 22, 6, 23, 6, 21, 5, 20, 5, 19, 5, 19, 4, 18,
4, 17, 4, 20, 3, 21, 3, 22, 3, 20, 2, 19, 2, 18, 2, 19, 1, 20, 1, 21, 1, 19,
0, 18, 0, 10, 0, 4, 1);
// Very basic form logic
ClientSize = new System.Drawing.Size(GridWidth * 20, GridHeight * 20);
DoubleBuffered = true;
Paint += ExampleProgram_Paint;
// Add a new point to the form (commented out)
// MouseUp += ExampleProgram_MouseUp_AddPoint;
// Draw the trail we find
MouseUp += ExampleProgram_MouseUp_AddTrail;
// Pick a starting point to start finding the trail from
// TODO: Left as an excersize for the reader to decide how to pick
// the starting point programatically
m_trail.Add(new Point(0, 4));
}
IEnumerable<Point> Border(Point pt)
{
// Return all points that border a give point
if (pt.X > 0)
{
if (pt.Y > 0)
{
yield return new Point(pt.X - 1, pt.Y - 1);
}
yield return new Point(pt.X - 1, pt.Y);
if (pt.Y < GridHeight - 1)
{
yield return new Point(pt.X - 1, pt.Y + 1);
}
}
if (pt.Y > 0)
{
yield return new Point(pt.X, pt.Y - 1);
}
if (pt.Y < GridHeight - 1)
{
yield return new Point(pt.X, pt.Y + 1);
}
if (pt.X < GridWidth - 1)
{
if (pt.Y > 0)
{
yield return new Point(pt.X + 1, pt.Y - 1);
}
yield return new Point(pt.X + 1, pt.Y);
if (pt.Y < GridHeight - 1)
{
yield return new Point(pt.X + 1, pt.Y + 1);
}
}
}
void AddPoints(params int[] points)
{
// Helper to add a bunch of points to our list of points
for (int i = 0; i < points.Length; i += 2)
{
m_points.Add(new Point(points[i], points[i + 1]));
}
}
void ExampleProgram_MouseUp_AddTrail(object sender, MouseEventArgs e)
{
// Calculate the trail
while (true)
{
// Find the best point for the next point
int bestCount = 0;
Point best = new Point();
// At the current end point, test all the points around it
foreach (var pt in Border(m_trail[m_trail.Count - 1]))
{
// And for each point, see how many points this point borders
int count = 0;
if (m_points.Contains(pt) && !m_trail.Contains(pt))
{
foreach (var test in Border(pt))
{
if (m_points.Contains(test))
{
if (m_trail.Contains(test))
{
// This is a point both in the original cloud, and the current
// trail, so give it a negative weight
count--;
}
else
{
// We haven't visited this point, so give it a positive weight
count++;
}
}
}
}
if (count > bestCount)
{
// This point looks better than anything we've found, so
// it's the best one so far
bestCount = count;
best = pt;
}
}
if (bestCount <= 0)
{
// We either didn't find anything, or what we did find was bad, so
// break out of the loop, we're done
break;
}
m_trail.Add(best);
}
Invalidate();
}
void ExampleProgram_MouseUp_AddPoint(object sender, MouseEventArgs e)
{
// Just add the point, and dump it out
int x = (int)Math.Round((((double)e.X) - 10.0) / 20.0, 0);
int y = (int)Math.Round((((double)e.Y) - 10.0) / 20.0, 0);
m_points.Add(new Point(x, y));
Debug.WriteLine("m_points.Add(new Point(" + x + ", " + y + "));");
Invalidate();
}
void ExampleProgram_Paint(object sender, PaintEventArgs e)
{
// Simple drawing, just draw a grid, and the points
e.Graphics.Clear(Color.White);
for (int x = 0; x < GridWidth; x++)
{
e.Graphics.DrawLine(Pens.Black, x * 20 + 10, 0, x * 20 + 10, ClientSize.Height);
}
for (int y = 0; y < GridHeight; y++)
{
e.Graphics.DrawLine(Pens.Black, 0, y * 20 + 10, ClientSize.Width, y * 20 + 10);
}
foreach (var pt in m_points)
{
e.Graphics.FillEllipse(Brushes.Black, (pt.X * 20 + 10) - 5, (pt.Y * 20 + 10) - 5, 10, 10);
}
foreach (var pt in m_trail)
{
e.Graphics.FillEllipse(Brushes.Red, (pt.X * 20 + 10) - 6, (pt.Y * 20 + 10) - 6, 12, 12);
}
}
}
}
You might want to consider treating your coordinates as a binary image and apply some Morphological techniques to the image.
Thinning might give you good results, but processing like this can be tricky to get working well in a wide range of cases.
Let's say I have an object:
{Derp: 17, Herp: 2, Asd: 5, Foo: 8, Qwe: 12}
And I need to sort it by value. What I'm looking to get is:
{Derp: 17, Qwe: 12, Foo: 8, Asd: 5, Herp: 2}
I'd like to use lodash for it. When I use _.sortBy it doesn't retain the keys how ever:
_.sortBy({Derp: 17, Herp: 2, Asd: 5, Foo: 8, Qwe: 12}).reverse();
// [17, 12, 8, 5, 2]
Hell, I'd even settle for just the array of keys, but still sorted by the value in the input:
['Derp', 'Herp', 'Foo', 'Asd', 'Qwe']
This worked for me
o = _.fromPairs(_.sortBy(_.toPairs(o), 1).reverse())
Here's an example:
var o = {
a: 2,
c: 3,
b: 1
};
o = _.fromPairs(_.sortBy(_.toPairs(o), 1).reverse())
console.log(o);
<script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script>
I was struggling with a similar problem and I was able to solve it doing some transforms with lodash. For your problem it would be:
let doo = {Derp: 17, Herp: 2, Asd: 5, Foo: 8, Qwe: 12};
let foo = _.chain(doo)
.map((val, key) => {
return { name: key, count: val }
})
.sortBy('count')
.reverse()
.keyBy('name')
.mapValues('count')
.value();
console.log(foo);
// Derp: 17, Qwe: 12, Foo: 8, Asd: 5, Herp: 2 }
You could try like this,
_.mapValues(_.invert(_.invert(obj)),parseInt);
Object {Herp: 2, Asd: 5, Foo: 8, Qwe: 12, Derp: 17}
or
var obj = {Derp: 17, Herp: 2, Asd: 5, Foo: 8, Qwe: 12}
var result = _.reduceRight(_.invert(_.invert(obj)), function(current, val, key){
current[key] = parseInt(val);
return current;
},{});
Object {Derp: 17, Qwe: 12, Foo: 8, Asd: 5, Herp: 2}
or
Using Chain methods:
_.chain(obj).invert().invert().reduceRight(function(current, val, key){
current[key] = parseInt(val);
return current;
},{}).value()
Object {Derp: 17, Qwe: 12, Foo: 8, Asd: 5, Herp: 2}
Note: It depends on browser usally object properties order is not gurrantee in most case.
Vanilla ES6 version
const obj = {
a: 2,
c: 3,
b: 1
}
const sorted = Object.entries(obj)
.sort((a, b) => a[1] <= b[1] ? -1 : 1)
.reduce((acc, pair) => {
acc[pair[0]] = pair[1]
return acc
}, {})
// Output: { b: 1, a: 2, c: 3 }
This'll also let you access the sort callback, allowing for more granular sorting on deeper object properties.
Simple Vanila javascript approch
Object.fromEntries(Object.entries(obj).sort((a, b) => a[1] - b[1]));
I have a matrix, IEnumerable<IEnumerable<int>> matrix, for example:
{ {10,23,16,20,2,4}, {22,13,1,33,21,11 }, {7,19,31,12,6,22}, ... }
and another array:
int[] arr={ 10, 23, 16, 20}
I want to filter the matrix on the condition that I group all rows of the matrix which contain the same number of elements from arr.
That is to say the first row in the matrix {10,23,16,20,2,4} has 4 numbers from arr, this array should be grouped with the rest of the rows with 4 numbers from arr.
better to use linq, thank you very much!
This worked for me:
private static void Main(string[] args)
{
int[] searchNums = new int[] {10, 23, 16, 20};
var groupByCount = from o in lists
group o by o.Count(num => searchNums.Contains(num)) into g
orderby g.Key
select g;
foreach(var grouping in groupByCount)
{
int countSearchNums = grouping.Key;
Console.WriteLine("Lists that have " + countSearchNums + " of the numbers:");
foreach(IEnumerable<int> list in grouping)
{
Console.WriteLine("{{ {0} }}", String.Join(", ", list.Select(o => o.ToString()).ToArray()));
}
}
Console.ReadKey();
}
private static List<List<int>> lists = new List<List<int>>
{
new List<int> {10, 23, 16, 20, 2, 4},
new List<int> {22, 13, 1, 33, 21, 11},
new List<int> {7, 19, 31, 12, 6, 22},
new List<int> {10, 13, 31, 12, 6, 22},
new List<int> {10, 19, 20, 16, 6, 22},
new List<int> {10},
new List<int> {10, 13, 16, 20},
};
Output:
Lists that have 0 of the numbers:
{ 22, 13, 1, 33, 21, 11 }
{ 7, 19, 31, 12, 6, 22 }
Lists that have 1 of the numbers:
{ 10, 13, 31, 12, 6, 22 }
{ 10 }
Lists that have 3 of the numbers:
{ 10, 19, 20, 16, 6, 22 }
{ 10, 13, 16, 20 }
Lists that have 4 of the numbers:
{ 10, 23, 16, 20, 2, 4 }