Motivated by https://benhoyt.com/writings/count-words/ , I have played a bit with rewriting an internal log analysis script in several languages (I will not go as far as in the article!).
After Go (by myself) and Rust (with some help from SO), I am currently stuck with Zig. I have more or less understood https://github.com/benhoyt/countwords/blob/master/simple.zig but still having a hard time with translating my original along these lines... Notably, using a Hash with tuple keys, handling name of months in parsing and printing...
Original script in Python:
import sys
months = { "Jan": 1, "Feb": 2, "Mar": 3, "Apr": 4, "May": 5, "Jun": 6,
"Jul": 7, "Aug": 8, "Sep": 9, "Oct": 10, "Nov": 11, "Dec": 12 }
months_r = { v:k for k,v in months.items() }
totals = {}
for line in sys.stdin:
if "redis" in line and "Partial" in line:
f1, f2 = line.split()[:2]
w = (months[f1], int(f2))
totals[w] = totals.get(w, 0) + 1
for k in sorted(totals.keys()):
print(months_r[k[0]], k[1], totals[k])
Could someone fluent with recent Zig give a hand?
Thanks a lot!
Solution from the Zig Forum
const std = #import("std");
const Key = struct { month: u4, day: u5 };
fn keyHash(key: Key) u64 {
return #as(u64, key.month) << 32 | #as(u64, key.day);
}
const Totals = std.HashMap(
Key,
usize,
keyHash,
std.hash_map.getAutoEqlFn(Key),
std.hash_map.default_max_load_percentage,
);
const Item = struct { key: Key, count: usize };
fn itemSort(context: void, lhs: Item, rhs: Item) bool {
return keyHash(lhs.key) < keyHash(rhs.key);
}
// zig fmt: off
const months = std.ComptimeStringMap(u4, .{
.{ "Jan", 1 }, .{ "Feb", 2 }, .{ "Mar", 3 },
.{ "Apr", 4 }, .{ "May", 5 }, .{ "Jun", 6 },
.{ "Jul", 7 }, .{ "Aug", 8 }, .{ "Sep", 9 },
.{ "Oct", 10 }, .{ "Nov", 11 }, .{ "Dec", 12 },
});
const months_r = [_][]const u8{
"(padding)",
"Jan", "Feb", "Mar",
"Apr", "May", "Jun",
"Jul", "Aug", "Sep",
"Oct", "Nov", "Dec",
};
// zig fmt: on
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer if (gpa.deinit()) std.log.err("memory leak detected", .{});
const allocator = &gpa.allocator;
var totals = Totals.init(allocator);
defer totals.deinit();
const stdin = std.io.bufferedReader(std.io.getStdIn().reader()).reader();
var buf: [4096]u8 = undefined;
while (try stdin.readUntilDelimiterOrEof(&buf, '\n')) |line| {
if (std.mem.indexOf(u8, line, "redis") == null or std.mem.indexOf(u8, line, "Partial") == null)
continue;
var it = std.mem.tokenize(line, &std.ascii.spaces);
const month = months.get(it.next().?).?;
const day = try std.fmt.parseUnsigned(u5, it.next().?, 10);
const res = try totals.getOrPut(.{ .month = month, .day = day });
if (res.found_existing)
res.entry.value += 1
else
res.entry.value = 1;
}
var stdout = std.io.bufferedWriter(std.io.getStdOut().writer());
defer stdout.flush() catch std.log.err("stdout flushing failed", .{});
const out = stdout.writer();
var items = try allocator.alloc(Item, totals.count());
defer allocator.free(items);
{
var it = totals.iterator();
var i: usize = 0;
while (it.next()) |kv| : (i += 1) {
items[i] = .{ .key = kv.key, .count = kv.value };
}
}
std.sort.sort(Item, items, {}, itemSort);
for (items) |it| {
try out.print("{s} {d} {d}\n", .{ months_r[it.key.month], it.key.day, it.count });
}
}
Related
I am trying to make a table and want to change a value in that table for a particular key. The thing is when I do change the key it does change for all the keys.
function dump(o, nb)
if nb == nil then
nb = 0
end
if type(o) == 'table' then
local s = ''
for i = 1, nb + 1, 1 do
s = s .. " "
end
s = '{\n'
for k,v in pairs(o) do
if type(k) ~= 'number' then k = '"'..k..'"' end
for i = 1, nb, 1 do
s = s .. " "
end
s = s .. '['..k..'] = ' .. dump(v, nb + 1) .. ',\n'
end
for i = 1, nb, 1 do
s = s .. " "
end
return s .. '}'
else
return tostring(o)
end
end
Config={}
PlayersStatusTable={}
Config.DefaultStatus = {
hunger = 1000000,
thirst = 1000000,
}
local timeNow = os.clock()
PlayersStatusTable[12] = Config.DefaultStatus
PlayersStatusTable[112] = Config.DefaultStatus
PlayersStatusTable[54] = Config.DefaultStatus
for playerId, details in pairs(PlayersStatusTable) do
print("playerid1",playerId)
print(dump(PlayersStatusTable))
print(dump(PlayersStatusTable[112]))
print(dump(PlayersStatusTable[112].hunger))
PlayersStatusTable[112].hunger = 5
end
the output is this:
playerid1 112
{
[112] = {
["thirst"] = 1000000,
["hunger"] = 1000000,
},
[54] = {
["thirst"] = 1000000,
["hunger"] = 1000000,
},
[12] = {
["thirst"] = 1000000,
["hunger"] = 1000000,
},
}
{
["thirst"] = 1000000,
["hunger"] = 1000000,
}
1000000
playerid1 54
{
[112] = {
["thirst"] = 1000000,
["hunger"] = 5,
},
[54] = {
["thirst"] = 1000000,
["hunger"] = 5,
},
[12] = {
["thirst"] = 1000000,
["hunger"] = 5,
},
}
{
["thirst"] = 1000000,
["hunger"] = 5,
}
5
playerid1 12
{
[112] = {
["thirst"] = 1000000,
["hunger"] = 5,
},
[54] = {
["thirst"] = 1000000,
["hunger"] = 5,
},
[12] = {
["thirst"] = 1000000,
["hunger"] = 5,
},
}
{
["thirst"] = 1000000,
["hunger"] = 5,
}
5
I just want the hunger of id 112 to be 5.
You're assigning the same table to all 3 keys, so they all point to the same table that's being changed. You need to ensure that you're creating a new table when you assign to each key.
local function shallowCopy(t)
local result = {}
for k, v in pairs(t) do
result[k] = v
end
return result
end
PlayersStatusTable[12] = shallowCopy(Config.DefaultStatus)
I want to write an algorithm that converts integer numbers to roman numbers and supports any positive number in dart.
I can do this in Java using String builder and i tried to do it in dart but i failed.
so please if anyone could help me, that would be very much appreciated!
here is the java algorithm, maybe it would help:
public static int[] arabianRomanNumbers = new int[]{
1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1
};
public static String[] romanNumbers = new String[]{
"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"
};
public String intToRoman(int num) {
if (num < 0) return "";
else if (num == 0) return "nulla";
StringBuilder builder = new StringBuilder();
for (int a = 0; a < arabianRomanNumbers.length; a++) {
int times = num / arabianRomanNumbers[a]; // equals 1 only when arabianRomanNumbers[a] = num
// executes n times where n is the number of times you have to add
// the current roman number value to reach current num.
builder.append(romanNumbers[a].repeat(times));
num -= times * arabianRomanNumbers[a]; // subtract previous roman number value from num
}
return builder.toString();
}
StringBuilder is called StringBuffer in Dart and does nearly the same but with a little different interface which you can read more about in the API documentation:
https://api.dart.dev/stable/2.7.1/dart-core/StringBuffer-class.html
With this knowledge, I have converted your Java code into Dart:
const List<int> arabianRomanNumbers = [
1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1
];
const List<String> romanNumbers = [
"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"
];
String intToRoman(int input) {
var num = input;
if (num < 0) {
return "";
}
else if (num == 0) {
return "nulla";
}
final builder = StringBuffer();
for (var a = 0; a < arabianRomanNumbers.length; a++) {
final times = (num / arabianRomanNumbers[a]).truncate(); // equals 1 only when arabianRomanNumbers[a] = num
// executes n times where n is the number of times you have to add
// the current roman number value to reach current num.
builder.write(romanNumbers[a] * times);
num -= times * arabianRomanNumbers[a]; // subtract previous roman number value from num
}
return builder.toString();
}
void main() {
for (var i = 0; i <= 1000; i++) {
print('$i => ${intToRoman(i)}');
}
}
I'm trying to dynamically set the width of each x point based on the number of non-zero stacks with that x value.
Example:
What I have:
What I want:
I want to get rid of the empty spaces by lowering the width of each date. (Sep 7 should have width 2, Sep 8 and Sep 9 should have width 1, instead of all 3 dates having width 3)
Here's a more extreme example, lots of wasted space:
I've looked into variwide charts but I can't seem to find an example of a variwide chart with both stacking and grouping.
The closest question I was able to find on stackoverflow is Display Different Number of Groups in Highcharts Stacked Column Graph but that answer doesn't change the width of the points, it just centers the bars.
JSFiddle: http://jsfiddle.net/t3z76o4b/3/
$(function() {
$('#container').highcharts({
chart: {
type: 'column',
},
legend: {
enabled: false
},
title: {
text: 'Fruits by day'
},
xAxis: {
type: 'category',
labels: {
rotation: -45,
formatter: function() {
var placeholder = Number(this.value);
if (!!placeholder) {
return ""
}
//var obj = data[this.value];
if (this.axis.series[0].levelNumber == 1 && !this.isFirst) {
return '';
} else {
return this.value;
}
}
},
crosshair: true,
},
plotOptions: {
series: {
stacking: 'normal'
}
},
series: [{
name: "Apples",
stack: "Apples",
date: "7 Sep 2018",
data: [{
color: "rgba(51,193,59,1)",
name: "7 Sep 2018",
y: 1
},
{
color: "rgba(51,193,50,0.4)",
name: "7 Sep 2018",
y: 2
}],
},
{
name: "Blueberries",
stack: "Blueberries",
date: "7 Sep 2018",
data: [{
color: "rgba(51,50,250,1)",
name: "7 Sep 2018",
y: 3
},
{
color: "rgba(51,50,250,0.4)",
name: "7 Sep 2018",
y: 1
}],
},
{
name: "Oranges",
stack: "Oranges",
date: "8 Sep 2018",
data: [{
color: "rgba(250,193,10,0.5)",
name: "8 Sep 2018",
y: 1
}, ],
},
{
name: "Blueberries",
stack: "Blueberries",
date: "9 Sep 2018",
data: [{
color: "rgba(51,50,250,1)",
name: "9 Sep 2018",
y: 2
}],
},
]
});
});
In the above JSFiddle, each series element represents a certain fruit on a certain day:
series[ 0] = Apples on Sep 7 2018
series[ 1] = Blueberries on Sep 7 2018
series[ 2] = Oranges on Sep 8 2018
series[ 3] = Blueberries on Sep
9 2018
Thanks in advance!
Unfortunately, Highcharts calculate groups space as xAxis width divided by categories length. So this space will be always equal among categories. The chart as you showed above requires a lot of changes in the core Highcharts functions and it is tricky to achieve.
Only centring columns in the group can be done with a bit of custom code:
var stacks = [
'section 1',
'section 2',
'section 3',
'section 4',
'section 5',
'section 6',
'section 7'
];
var categoriesStacksColl = [];
var seriesStackColl = {};
function calculateColumnTranslate(params) {
var m = params.stackLen / 2 + 0.5, // middle bar + offset to calc
barIndex = params.stackIndex,
a = Math.abs(barIndex - m), // bar offset from the middle point
barW = params.barW,
p = params.padding,
posX,
translateX;
if (barIndex === m) {
posX = -barW / 2;
} else if (barIndex > m) {
posX = a * barW + a * p - barW / 2;
} else {
posX = -a * barW - a * p - barW / 2;
}
translateX = posX - params.offset;
return translateX;
}
// Inside Highcharts options
chart: {
type: 'column',
events: {
load: function() {
var chart = this,
series = chart.series,
categoriesLen = chart.xAxis[0].tickPositions.length,
changeWidthFlag = false,
seriesPoints,
nextSeriesPoints,
stack,
length,
arrIndex,
i,
j;
categoriesStacksColl = [];
// Init stacks per categories array
for (j = 0; j < categoriesLen; j++) {
categoriesStacksColl.push(stacks.slice());
}
series.forEach(function(singleSeries) {
stack = singleSeries.options.stack;
if (!seriesStackColl[stack]) {
seriesStackColl[stack] = [];
}
seriesStackColl[stack].push(singleSeries);
});
stacks.forEach(function(initStack) {
seriesPoints = seriesStackColl[initStack][0].points;
length = seriesStackColl[initStack].length;
seriesPoints.forEach(function(point, index) {
if (!point.y && length === 1) {
// increase column width
changeWidthFlag = true;
} else if (!point.y && length > 1) {
changeWidthFlag = true;
for (i = 1; i < length; i++) {
nextSeriesPoints = seriesStackColl[initStack][i].points;
if (nextSeriesPoints[index].y) {
changeWidthFlag = false;
}
}
}
// when all points in category stack are null
if (changeWidthFlag) {
arrIndex = categoriesStacksColl[index].indexOf(initStack);
categoriesStacksColl[index].splice(arrIndex, 1);
changeWidthFlag = false;
}
});
});
},
render: function() {
var chart = this,
series = chart.series[0],
columnMetrics = series.columnMetrics,
barW = columnMetrics.width,
barOffsets = {},
offsets = [],
columnsToTranslate = [],
offsetMin = 0,
offsetMax = 0,
columnsGroupLen = stacks.length,
offset,
columnsGroupWidth,
padding,
point,
pointOffset,
stackIndex,
stackLen,
pointOffsetTemp,
translateBarX;
stacks.forEach(function(stack) {
if (seriesStackColl[stack][0].visible) {
offset = seriesStackColl[stack][0].columnMetrics.offset;
offsetMax = offsetMax < offset ? offset : offsetMax;
offsetMin = offsetMin > offset ? offset : offsetMin;
barOffsets[stack] = offset;
offsets.push(offset);
}
});
columnsGroupWidth = Math.abs(offsetMin) + Math.abs(offsetMax) + barW;
padding = (columnsGroupWidth - columnsGroupLen * barW) / (columnsGroupLen - 1);
categoriesStacksColl.forEach(function(cat, index) {
if (cat.length < stacks.length) {
columnsToTranslate.push({
index: index,
stack: cat
});
}
});
columnsToTranslate.forEach(function(elem) {
stackIndex = 0;
pointOffsetTemp = 0;
chart.series.forEach(function(singleSeries) {
point = singleSeries.points[elem.index];
if (point.y && singleSeries.visible) {
pointOffset = point.series.columnMetrics.offset;
stackLen = elem.stack.length;
if (pointOffsetTemp !== pointOffset) {
pointOffsetTemp = pointOffset;
stackIndex++;
}
translateBarX = calculateColumnTranslate({
padding: padding,
barW: barW,
offset: pointOffset,
stackIndex: stackIndex,
stackLen: stackLen
});
point.graphic.translate(translateBarX);
}
});
});
}
}
}
Demo:
https://jsfiddle.net/wchmiel/9eb74hys/2/
Defined an own table layouts using pdfmake.js. On print I want per page to contain 7 rows(fixed).I have tried adjusting the height and width of the table cell to contain 7 rows but however if the data in table cell increases the page accumulates with less/more no.of rows.
//layout of the table:
var tablelist={
style: 'tableExample',
table: {
dontBreakRows: true,
widths: [ 20,55,55,55,55,55,55,55,55,55,55,55,55],
headerRows: 1,
body: body
},
layout: {
hLineWidth: function (i, node) {
return (i === 0 || i === node.table.body.length) ? 1 : 1;
},
vLineWidth: function (i, node) {
return (i === 0 || i === node.table.widths.length) ? 1: 1;
},
hLineColor: function (i, node) {
return (i === 0 || i === node.table.body.length) ? 'gray' : 'gray';
},
vLineColor: function (i, node) {
return (i === 0 || i === node.table.widths.length) ? 'gray' : 'gray';
},
},
}
return tablelist;
}
//pushing the table header and other data to the table body
$scope.makePrintTable = function(){
var headers = {
col_1:{ text: 'Day', style: 'tableHeader',rowSpan: 1, alignment: 'center',margin: [0, 8, 0, 0] },
col_2:{ text: 'Date', style: 'tableHeader',rowSpan: 1, alignment: 'center',margin: [0, 8, 0, 0] },
col_3:{ text: '0600-0800', style: 'tableHeader',rowSpan: 1, alignment: 'center',margin: [0, 8, 0, 0] },
.
.
.//Similarly till col_13
col_13:{ text: '1700-1800', style: 'tableHeader',rowSpan: 1, alignment: 'center' ,margin: [0, 8, 0, 0]},
}
body = [];
var row = new Array();
for (var key in headers) {
row.push( headers[key] );
}
body.push(row);
for ( var j=0 ; j< $scope.table.length; j++){
var tableEach={ };
tableEach= $scope.table[j];
/*This for Genarating Object variables*/
for (var i = 1; i < 3; i++) {
window["obj"+i] = new Object();
}
var row = new Array();
var slNoValue = tableEach.slNo;
/*This is for slNo */
obj1["text"] = slNoValue;
obj1["style"]= "cellswidth";
row.push(obj1);
/*This is for Date */
var dateValue = new Date(tableEach.date);
obj2["text"]= dateValue.getDate() + '-' + basicFormats.getMonthName(dateValue.getMonth() )+ '-' + dateValue.getFullYear()+','+ basicFormats.getDayName(dateValue.getDay());
obj2["style"]= "cellswidth";
row.push(obj2);
/*This is for remaining columns (i ranges from 6 to 17 (time in 24hrs clock format) ) */
for(var i=6 ; i<=17 ; i++){
var obj={};
var hourValue = "hour_"+i+"_"+(i+1)+"_value";
var hourValueColor = "hour_"+i+"_"+(i+1)+"_"+"color_value";
hourValue = ( tableEach["hour_"+i] == undefined ? '':(tableEach["hour_"+i]));
hourValueColor =(tableEach["hour_"+i+"_colour"] == undefined ? '#ffffff':(tableEach["hour_"+i+"_colour"]));
obj["text"] = hourValue;
obj["fillColor"] = hourValueColor;
obj["style"] = "cellswidth";
row.push(obj);
console.log(obj);
}
// if( j!= 0 && j % 7 == 0){
// pageBreak : 'before'
// }
}
body.push(row);
}
};
//CSS for tablecells
cellswidth : {
fontSize: 10,
// color:'gray',
bold: true,
alignment: 'center',
margin: [0, 12.55, 0, 12.75],
},
You can use pageBreak function for it:
pageBreakBefore: function(currentNode, followingNodesOnPage, nodesOnNextPage, previousNodesOnPage) {
//Here you can change the criteria according to your requirements
if (currentNode.index % 7 === 0)) {
return true;
}
return false;
},
I have a Highstock chart with three lines. When I add data, it will at in semi regular cases let the max range handle move off the right side, and then stay put instead of staying glued to the right side as expected. This behavior is not wanted.
Before it slips:
After it slips:
I have made a simplified example
https://jsfiddle.net/eskil_saatvedt/rdwdbht1/3/
HTML
<script src="https://code.highcharts.com/stock/highstock.js"></script>
<div id="container" style="height: 400px; min-width: 310px"></div>
Javascript
$(function() {
Highcharts.setOptions({
global: {
useUTC: false
}
});
// Create the chart
$('#container').highcharts('StockChart', {
chart: {
type: 'line',
},
rangeSelector: {
buttons: [{
count: 1,
type: 'minute',
text: '1M'
}, {
count: 5,
type: 'minute',
text: '5M'
}, {
type: 'all',
text: 'All'
}],
inputEnabled: false,
selected: 2
},
title: {
text: 'Live random data'
},
exporting: {
enabled: false
},
series: [{
name: 'Random data',
data: (function() {
// generate an array of random data
var data = [],
time = (new Date()).getTime();
data.push([
time +1 * 1000,
Math.round(Math.random() * 100)
]);
return data;
}())
},
{
name: 'Random data2',
data: (function() {
// generate an array of random data
var data = [],
time = (new Date()).getTime();
data.push([
time +1 * 1000,
Math.round(Math.random() * 100)
]);
return data;
}())
},
{
name: 'Random data3',
data: (function() {
// generate an array of random data
var data = [],
time = (new Date()).getTime();
data.push([
time +1 * 1000,
Math.round(Math.random() * 100)
]);
return data;
}())
}
]
});
});
function UpdateData() {
var chart = $('#container').highcharts();
var x = (new Date()).getTime(), // current time
y = Math.round(Math.random() * 100),
k = Math.round(Math.random() * 100)+50,
z = Math.round(Math.random() * 100)+20;
chart.series[0].addPoint([x, y], false, false);
chart.series[1].addPoint([x, z], false, false);
chart.series[2].addPoint([x, k], false, false);
chart.redraw();
}
setInterval(function() {
UpdateData();
}, 1000);
Normally I would display 2 temperatures and gain, using it for room heat control.
You need to call setExtremes()](http://api.highcharts.com/highcharts#Axis.setExtremes) function after adding point with new range.
function UpdateData() {
var chart = $('#container').highcharts(),
min = chart.xAxis[0].dataMin,
max = chart.xAxis[0].dataMax,
x = (new Date()).getTime(), // current time
y = Math.round(Math.random() * 100),
k = Math.round(Math.random() * 100) + 50,
z = Math.round(Math.random() * 100) + 20;
chart.series[0].addPoint([x, y], false, false);
chart.series[1].addPoint([x, z], false, false);
chart.series[2].addPoint([x, k], false, false);
chart.xAxis[0].setExtremes(min,x);
}
Example:
- https://jsfiddle.net/xh1sjk3L/
Thanks to Sebastian.
By using max = chart.xAxis[0].userMax I was able to set the max value to max if it is close to the side. In the example 1 second
function UpdateData() {
var chart = $('#container').highcharts();
var userMax = chart.xAxis[0].userMax; // <- change
var x = (new Date()).getTime(), // current time
y = Math.round(Math.random() * 100),
k = Math.round(Math.random() * 100)+50,
z = Math.round(Math.random() * 100)+20;
chart.series[0].addPoint([x, y], false, false);
chart.series[1].addPoint([x, z], false, false);
chart.series[2].addPoint([x, k], false, false);
chart.redraw(); // Redraw it again, as the left handle position I want is most often correct after the redraw.
// ----- change --------
var deltaX = x - userMax;
if (deltaX < 1000){ // the handle was closer to the end than 1 second
chart.xAxis[0].setExtremes(chart.xAxis[0].min,x);
}
}