Print the second largest number on the list - dart

I need to print the second largest number on the list, the output from the below code is all elements in the list except the first and the last one.
What is the mistake?
void main () {
List a = [9,6,4,10,13,2,3,5];
a.sort;
for(int x in a){
for (int max in a){
for (int second_last in a){
if (x > max) {
second_last = max;
max = x;
} else if (x > second_last && x != max) {
second_last = x;
print(second_last);
}
}
}
}
}

There are a few things wrong with your code:
You're not actually sorting the list. The sort method returns a new sorted list, it doesn't sort the existing list. So you need to do:
a = a.sort;
You're iterating over the list 3 times when you only need to iterate over it once.
You're not keeping track of the second largest number, you're just printing it out as you find it.
You're not checking for duplicates. If there are duplicate numbers in the list, your code will print them out multiple times.
Here's a corrected pseudo-code
void main() {
List a = [9, 6, 4, 10, 13, 2, 3, 5];
a.sort;
int max = a[0];
int second_last = a[0];
for (int x in a) {
if (x > max) {
second_last = max;
max = x;
} else if (x > second_last && x != max) {
second_last = x;
}
}
print(second_last);
}

I need to print the second largest number on the list
Sort the array (desc).
Access the second element.
List a = [9, 6, 4, 10, 13, 2, 3, 5];
a.sort((a, z) => z - a);
// final b = a.toList()..sort(...); if you do not want to modify the original array.
print(a.take(2)); // [13, 10]
print(a.take(2)[1]); // [10]
print(a.take(2).skip(1)); // [10]
print(a.skip(1).first); // [10]

You are missing () on sort. You can do
void main() {
List a = [9, 6, 4, 10, 13, 2, 3, 5];
a.sort();
print(a[a.length - 2]); //get second large item
List b = [9, 6, 4, 10, 13, 2, 3, 5];
//or like revese sort
b.sort((a, b) => b.compareTo(a));
print(b[1]);
}

If you find a solution that is without using the sort function, and also works with all possible conditions,
so you can use this solution as well,
void main(){
var list =[9,6,4,10,13,2,3,5,13];
var secondLargest = findSecLargest(list);
print(secondLargest);
}
findSecLargest(List<int> list) {
var secLargest =-1;
var largest=list[0];
for(int i = 1 ; i < list.length ; i ++){
if(largest<list[i]){
secLargest = largest;
largest = list[i];
}else if(secLargest<list[i] && list[i]!=largest){
secLargest = list[i];
}
}
return secLargest;
}

Related

Dart: how to convert a column letter into number

Currently using Dart with gsheets_api, which don't seem to have a function to convert column letters to numbers (column index)
As an example , this is what I use with AppScript (input: column letter, output: column index number):
function Column_Nu_to_Letter(column_nu)
{
var temp, letter = '';
while (column_nu > 0)
{
temp = (column_nu - 1) % 26;
letter = String.fromCharCode(temp + 65) + letter;
column_nu = (column_nu - temp - 1) / 26;
}
return letter;
};
This is the code I came up for Dart, it works, but I am sure there is a more elegant or correct way to do it.
String colLetter = 'L'; //Column 'L' as example
int c = "A".codeUnitAt(0);
int end = "Z".codeUnitAt(0);
int counter = 1;
while (c <= end) {
//print(String.fromCharCode(c));
if(colLetter == String.fromCharCode(c)){
print('Conversion $colLetter = $counter');
}
counter++;
c++;
}
// this output L = 12
Do you have any suggestions on how to improve this code?
First we need to agree on the meaning of the letters.
I believe the traditional approach is "A" is 1, "Z" is 26, "AA" is 27, "AZ" is 52, "BA" is 53, etc.
Then I'd probably go with something like these functions for converting:
int lettersToIndex(String letters) {
var result = 0;
for (var i = 0; i < letters.length; i++) {
result = result * 26 + (letters.codeUnitAt(i) & 0x1f);
}
return result;
}
String indexToLetters(int index) {
if (index <= 0) throw RangeError.range(index, 1, null, "index");
const _letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (index < 27) return _letters[index - 1];
var letters = <String>[];
do {
index -= 1;
letters.add(_letters[index.remainder(26)]);
index ~/= 26;
} while (index > 0);
return letters.reversed.join("");
}
The former function doesn't validate that the input only contains letters, but it works correctly for strings containing only letters (and it ignores case as a bonus).
The latter does check that the index is greater than zero.
A simplified version base on Irn's answer
int lettersToIndex(String letters) =>
letters.codeUnits.fold(0, (v, e) => v * 26 + (e & 0x1f));
String indexToLetters(int index) {
var letters = '';
do {
final r = index % 26;
letters = '${String.fromCharCode(64 + r)}$letters';
index = (index - r) ~/ 26;
} while (index > 0);
return letters;
}

how do I make an integer to roman algorithm in dart?

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)}');
}
}

How to find a random combination from given numbers that add up to another number in Swift?

Given a random set of positive integers A, find one random combination of int's that add up to N.
Ex.
A = [4, 2, 10, 8, 13, 1, ...]
N = 18
The possibilities are [10, 8], [4, 13, 1], etc.
The set A can also be any length and can only hold positive integers.
N can be any positive integer.
I only need one combination of numbers, not all of them. I would also like to pick randomly so if I'm given the same set, I wouldn't keep getting the same answer every time and I'm looking for the most efficient way I can do this programmatically in Swift.
You first need to create a method to find all possible subsets of your original collection as I posted here Subset sum Swift. Then you just need to check if any subset sum is equal to n:
extension RangeReplaceableCollection {
var subSets: [SubSequence] {
return isEmpty ? [SubSequence()] : dropFirst().subSets.lazy.flatMap { [$0, prefix(1) + $0] }
}
}
let a = [4, 2, 10, 8, 13, 1]
let n = 18
let matches = a.subSets.lazy.filter { $0.reduce(0,+) == n }
print("Matches:", Array(matches.map{Array($0)})) // Matches: [[10, 8], [4, 13, 1]]
You can also use a non recursive approach as you can see at another post I have made here Find all combination of string array in swift. Note that this second approach I did it in a way to do not consider an empty set a subset:
extension RangeReplaceableCollection {
var subSetsNotRecursive : [SubSequence] {
guard !isEmpty else { return [] }
let count = self.count
let n = 1 << count - 1
var subSequences: [SubSequence] = .init(repeating: SubSequence(), count: n-1)
(0 ..< n).map {
var counter = 0
for element in self {
if $0 & 1 << counter > 0 {
subSequences[$0-1].append(element)
}
counter += 1
}
}
return subSequences + [self[...]]
}
}
let matches2 = a.subSetsNotRecursive.lazy.filter { $0.reduce(0,+) == n }
print("Matches2:", Array(matches2.map{Array($0)})) // Matches2: [[10, 8], [4, 13, 1]]
Or expanding it further. If you are only interested on those sets that summed are equal to a certain value, you can check every time you finish creating your set if the sum of the elements that where appended are equal to the value you want:
extension RangeReplaceableCollection where Element: BinaryInteger {
func subSetsThatSummedAre(equalTo value: Element) -> [SubSequence] {
guard !isEmpty else { return [] }
let count = self.count
let n = 1 << count - 1
var subSets: [SubSequence] = []
(0 ..< n).map {
var counter = 0
var sum: Element = 0
var subSequence = SubSequence()
for element in self {
if $0 & 1 << counter > 0 {
subSequence.append(element)
sum += element
}
counter += 1
}
if sum == value {
subSets.append(subSequence)
}
}
if reduce(0, +) == value {
subSets.append(self[...])
}
return subSets
}
}
let matches4 = a.subSetsThatSummedAre(equalTo: n)
print("Matches4:", Array(matches4.map{Array($0)})) // Matches4: [[10, 8], [4, 13, 1]]

How to generate a sequence based on a different sequence

I have this sequence:
let wheel235 = [4; 2; 4; 2; 4; 6; 2; 6]
let wheel = seq { while true yield! wheel235 }
I'd like to build a second sequence that starts on a particular number, and each following number in that sequence is the previous number with the next item in the wheel sequence added to it. So if I started the sequence at 5, I would have 5, 9, 11, 15, 17, 21, 27, etc...
I can't quite wrap my head around how to do it.
For those familiar with it, it's obviously a number wheel for prime number generation, but I don't think knowing that would matter much for the answer. :)
You can do it with Seq.scan:
let wheel235 = [4; 2; 4; 2; 4; 6; 2; 6]
let wheel = seq { while true do yield! wheel235 }
let result = wheel |> Seq.scan (+) 5
# result will be 5, 9, 11, 15, 17, 21, 27, etc
I think that if you want to do this just using a sequence expression, you would need to use a mutable ref cell:
let wheel = seq {
let result = ref 5
yield !result
while true do
for x in wheel235 do
result := !result + x
yield !result
}
But I think a better way would be to combine your code to repeat wheel235 inifitely (after fixing the syntax error) with Seq.scan (as suggested bu LukeH):
let wheel = seq { while true do yield! wheel235 } |> Seq.scan (+) 5

Enumerate NSArray starting at givven index searching both ways (wrap around)

Example. I've got an array with 15 objects. I want to start enumerating from a given index. Say start at index 5 and then the index above, the index under, above, under etc... I do want it to wrap around.
So the order of indexes in my example would be. 5, 6, 4, 7, 3, 8, 2, 9, 1, 10, 0, 11, 14, 12, 13
It would be great to have a method signature similar to following line, but I don't require that to approva an answer:
- (void)enumerateFromIndex:(NSUInteger)index wrapAroundAndGoBothWays:(void (^)(id obj, NSUInteger idx, BOOL *stop))block
How can this be done? Would like to avoid copying array etc.
At this post we do it with no wrap around: Enumerate NSArray starting at givven index searching both ways (no wrap around)
Borrowing from #omz, here is the wrapping variant, which is even simpler:
#implementation NSArray (Extensions)
- (void)enumerateFromIndex:(NSUInteger)index wrapAroundAndGoBothWays:(void (^)(id obj, NSUInteger idx, BOOL *stop))block
{
BOOL stop = NO;
NSUInteger actual = index;
for (NSUInteger i = 0; i < self.count && !stop; i++) {
actual += (2*(i%2)-1)*i;
actual = (self.count + actual)%self.count;
block([self objectAtIndex:actual], actual, &stop);
}
}
#end
This is a mathematical problem. There is a nice solution. However, it involves sorting the list of indexes in advance.
The idea is to lay the integers from 0 to 15 out on a circle and taking the elements in the order they appear on an axis.
Since doing this in ObjC is so tedious, I present the python solution:
from math import pi, cos
def circlesort(N, start):
eps = 1e-8
res = range(N)
def f(x):
return -cos(2*pi*(x-start-eps)/N)
res.sort( lambda x,y:cmp(f(x), f(y)) )
return res
then
print circlesort(15, 5)
outputs
[5, 6, 4, 7, 3, 8, 2, 9, 1, 10, 0, 11, 14, 12, 13]
which is the desired result.
EDIT
Okay, here is a C implementation:
#include <stdlib.h>
#include <math.h>
#define sign(x) ((x)>0?1:(x)<0?-1:0)
void circlesort(int* values, int N, int start){
double f(int x)
{
return -cos(2*M_PI*((double)(x-start)-.25)/N);
}
int compare (const void * a, const void * b)
{
return sign( f(*(int*)a) - f(*(int*)b) );
}
qsort (values, N, sizeof(int), compare);
}
This will circlesort an array of integers of lenght N. Use it like this:
int i, N = 15;
int indexes[N];
for (i=0;i<N;i++)
indexes[i] = i;
circlesort(indexes, N, 5);
Now the array indexes is sorted in the desired order. Because there are nested functions, you should add -fnested-functions to the compiler flags.
EDIT 2
Considering the fact that there is a much simpler solution (see my other answer) this one is rather academic.

Resources